From 50fc30ec430c715963c1384aa5f9dbce87bc756d Mon Sep 17 00:00:00 2001
From: plebhash <plebhash@proton.me>
Date: Sun, 26 May 2024 14:17:57 -0300
Subject: [PATCH] standardize roles CLI

---
 roles/Cargo.lock                              | 338 ++++++++++++++++--
 roles/jd-client/Cargo.toml                    |   3 +-
 roles/jd-client/src/args.rs                   |  81 ++---
 roles/jd-client/src/lib/error.rs              |  96 +++--
 .../lib/{proxy_config.rs => jdc_config.rs}    |   4 +-
 roles/jd-client/src/lib/job_declarator/mod.rs |   6 +-
 roles/jd-client/src/lib/mod.rs                |   2 +-
 roles/jd-client/src/lib/status.rs             |  49 +--
 .../src/lib/upstream_sv2/upstream.rs          |  20 +-
 roles/jd-client/src/main.rs                   |  62 ++--
 roles/jd-server/Cargo.toml                    |   3 +-
 roles/jd-server/src/args.rs                   |  28 ++
 roles/jd-server/src/lib/error.rs              |  10 +
 roles/jd-server/src/lib/jds_config.rs         |  88 +++++
 roles/jd-server/src/lib/job_declarator/mod.rs |  17 +-
 roles/jd-server/src/lib/mod.rs                |  23 +-
 roles/jd-server/src/lib/status.rs             |   3 +
 roles/jd-server/src/main.rs                   | 102 +-----
 roles/mining-proxy/Cargo.toml                 |   3 +-
 roles/mining-proxy/src/args.rs                |  28 ++
 roles/mining-proxy/src/lib/error.rs           |  22 +-
 roles/mining-proxy/src/lib/mod.rs             |  14 +-
 roles/mining-proxy/src/lib/proxy_config.rs    |  14 +
 roles/mining-proxy/src/lib/upstream_mining.rs |  16 +-
 roles/mining-proxy/src/main.rs                |  99 +----
 roles/pool/Cargo.toml                         |   3 +-
 roles/pool/src/args.rs                        |  29 ++
 roles/pool/src/lib/error.rs                   |   8 +
 roles/pool/src/lib/mining_pool/mod.rs         |  71 ++--
 roles/pool/src/lib/mod.rs                     |   1 +
 roles/pool/src/lib/pool_config.rs             |  57 +++
 roles/pool/src/lib/status.rs                  |   3 +
 roles/pool/src/main.rs                        | 102 +-----
 roles/translator/Cargo.toml                   |   4 +-
 roles/translator/src/args.rs                  |  81 ++---
 .../src/lib/downstream_sv1/diff_management.rs |  44 +--
 .../src/lib/downstream_sv1/downstream.rs      |  12 +-
 roles/translator/src/lib/error.rs             | 122 +++----
 roles/translator/src/lib/mod.rs               |   2 +-
 roles/translator/src/lib/proxy/bridge.rs      |  26 +-
 roles/translator/src/lib/status.rs            |  79 ++--
 .../lib/{proxy_config.rs => tproxy_config.rs} |   2 +-
 .../src/lib/upstream_sv2/diff_management.rs   |  12 +-
 .../src/lib/upstream_sv2/upstream.rs          |  39 +-
 .../lib/upstream_sv2/upstream_connection.rs   |   6 +-
 roles/translator/src/main.rs                  |  19 +-
 46 files changed, 1032 insertions(+), 821 deletions(-)
 rename roles/jd-client/src/lib/{proxy_config.rs => jdc_config.rs} (97%)
 create mode 100644 roles/jd-server/src/args.rs
 create mode 100644 roles/jd-server/src/lib/jds_config.rs
 create mode 100644 roles/mining-proxy/src/args.rs
 create mode 100644 roles/mining-proxy/src/lib/proxy_config.rs
 create mode 100644 roles/pool/src/args.rs
 create mode 100644 roles/pool/src/lib/pool_config.rs
 rename roles/translator/src/lib/{proxy_config.rs => tproxy_config.rs} (98%)

diff --git a/roles/Cargo.lock b/roles/Cargo.lock
index 1c0dc4d8f2..3cfcdac277 100644
--- a/roles/Cargo.lock
+++ b/roles/Cargo.lock
@@ -52,12 +52,6 @@ dependencies = [
  "subtle",
 ]
 
-[[package]]
-name = "ahash"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
-
 [[package]]
 name = "ahash"
 version = "0.7.8"
@@ -316,6 +310,17 @@ version = "4.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
 
+[[package]]
+name = "async-trait"
+version = "0.1.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.61",
+]
+
 [[package]]
 name = "atomic-waker"
 version = "1.1.2"
@@ -437,6 +442,9 @@ name = "bitflags"
 version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "block-buffer"
@@ -594,7 +602,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
 [[package]]
 name = "codec_sv2"
-version = "1.0.1"
+version = "1.1.0"
 dependencies = [
  "binary_sv2",
  "buffer_sv2",
@@ -628,6 +636,46 @@ dependencies = [
  "crossbeam-utils",
 ]
 
+[[package]]
+name = "config"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be"
+dependencies = [
+ "async-trait",
+ "convert_case",
+ "json5",
+ "lazy_static",
+ "nom",
+ "pathdiff",
+ "ron",
+ "rust-ini",
+ "serde",
+ "serde_json",
+ "toml",
+ "yaml-rust",
+]
+
+[[package]]
+name = "const-random"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
+dependencies = [
+ "const-random-macro",
+]
+
+[[package]]
+name = "const-random-macro"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "tiny-keccak",
+]
+
 [[package]]
 name = "const_sv2"
 version = "1.0.0"
@@ -635,6 +683,15 @@ dependencies = [
  "secp256k1 0.28.2",
 ]
 
+[[package]]
+name = "convert_case"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
+dependencies = [
+ "unicode-segmentation",
+]
+
 [[package]]
 name = "cpufeatures"
 version = "0.2.12"
@@ -650,6 +707,12 @@ version = "0.8.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
 
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
 [[package]]
 name = "crypto-common"
 version = "0.1.6"
@@ -696,6 +759,15 @@ dependencies = [
  "crypto-common",
 ]
 
+[[package]]
+name = "dlv-list"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
+dependencies = [
+ "const-random",
+]
+
 [[package]]
 name = "env_logger"
 version = "0.7.1"
@@ -800,7 +872,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "framing_sv2"
-version = "1.0.0"
+version = "1.1.0"
 dependencies = [
  "binary_sv2",
  "buffer_sv2",
@@ -995,23 +1067,19 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.7.2"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 dependencies = [
- "ahash 0.3.8",
- "autocfg",
+ "ahash",
+ "serde",
 ]
 
 [[package]]
 name = "hashbrown"
-version = "0.11.2"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-dependencies = [
- "ahash 0.7.8",
- "serde",
-]
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
 
 [[package]]
 name = "hashbrown"
@@ -1207,7 +1275,9 @@ dependencies = [
  "async-recursion 0.3.2",
  "binary_sv2",
  "buffer_sv2",
+ "clap",
  "codec_sv2",
+ "config",
  "error_handling",
  "framing_sv2",
  "futures",
@@ -1218,7 +1288,6 @@ dependencies = [
  "serde",
  "stratum-common",
  "tokio",
- "toml",
  "tracing",
  "tracing-subscriber",
 ]
@@ -1230,7 +1299,9 @@ dependencies = [
  "async-channel 1.9.0",
  "binary_sv2",
  "buffer_sv2",
+ "clap",
  "codec_sv2",
+ "config",
  "const_sv2",
  "error_handling",
  "hashbrown 0.11.2",
@@ -1246,7 +1317,6 @@ dependencies = [
  "serde_json",
  "stratum-common",
  "tokio",
- "toml",
  "tracing",
  "tracing-subscriber",
 ]
@@ -1268,9 +1338,20 @@ dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "json5"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
+dependencies = [
+ "pest",
+ "pest_derive",
+ "serde",
+]
+
 [[package]]
 name = "key-utils"
-version = "1.0.0"
+version = "1.1.0"
 dependencies = [
  "bs58",
  "secp256k1 0.28.2",
@@ -1298,6 +1379,12 @@ version = "0.2.154"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
 
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
 [[package]]
 name = "linux-raw-sys"
 version = "0.3.8"
@@ -1335,6 +1422,12 @@ version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
 [[package]]
 name = "mining-device"
 version = "0.1.1"
@@ -1366,7 +1459,9 @@ dependencies = [
  "async-recursion 0.3.2",
  "binary_sv2",
  "buffer_sv2",
+ "clap",
  "codec_sv2",
+ "config",
  "const_sv2",
  "futures",
  "key-utils",
@@ -1377,7 +1472,6 @@ dependencies = [
  "serde",
  "stratum-common",
  "tokio",
- "toml",
  "tracing",
  "tracing-subscriber",
 ]
@@ -1443,6 +1537,16 @@ dependencies = [
  "secp256k1 0.28.2",
 ]
 
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
 [[package]]
 name = "nu-ansi-term"
 version = "0.46.0"
@@ -1512,6 +1616,16 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
 
+[[package]]
+name = "ordered-multimap"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e"
+dependencies = [
+ "dlv-list",
+ "hashbrown 0.13.2",
+]
+
 [[package]]
 name = "overload"
 version = "0.1.1"
@@ -1547,6 +1661,57 @@ dependencies = [
  "windows-targets 0.52.5",
 ]
 
+[[package]]
+name = "pathdiff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+
+[[package]]
+name = "pest"
+version = "2.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8"
+dependencies = [
+ "memchr",
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.61",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2 0.10.8",
+]
+
 [[package]]
 name = "pin-project"
 version = "1.1.5"
@@ -1652,7 +1817,9 @@ dependencies = [
  "async-recursion 1.1.1",
  "binary_sv2",
  "buffer_sv2",
+ "clap",
  "codec_sv2",
+ "config",
  "const_sv2",
  "error_handling",
  "hex",
@@ -1665,7 +1832,6 @@ dependencies = [
  "serde",
  "stratum-common",
  "tokio",
- "toml",
  "tracing",
  "tracing-subscriber",
 ]
@@ -1780,7 +1946,7 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
 
 [[package]]
 name = "roles_logic_sv2"
-version = "1.0.0"
+version = "1.1.0"
 dependencies = [
  "binary_sv2",
  "chacha20poly1305",
@@ -1796,6 +1962,18 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "ron"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
+dependencies = [
+ "base64",
+ "bitflags 2.5.0",
+ "serde",
+ "serde_derive",
+]
+
 [[package]]
 name = "rpc_sv2"
 version = "1.0.0"
@@ -1810,6 +1988,16 @@ dependencies = [
  "stratum-common",
 ]
 
+[[package]]
+name = "rust-ini"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091"
+dependencies = [
+ "cfg-if",
+ "ordered-multimap",
+]
+
 [[package]]
 name = "rustc-demangle"
 version = "0.1.24"
@@ -1925,6 +2113,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde_spanned"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "serde_sv2"
 version = "1.0.0"
@@ -2105,6 +2302,26 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "thiserror"
+version = "1.0.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.61",
+]
+
 [[package]]
 name = "thread_local"
 version = "1.1.8"
@@ -2115,6 +2332,15 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "tiny-keccak"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
+dependencies = [
+ "crunchy",
+]
+
 [[package]]
 name = "tokio"
 version = "1.37.0"
@@ -2160,11 +2386,36 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.5.6"
-source = "git+https://github.com/diondokter/toml-rs?rev=c4161aa#c4161aa70202b3992dbec79b76e7a8659713b604"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c"
 dependencies = [
- "hashbrown 0.7.2",
+ "indexmap",
  "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
 ]
 
 [[package]]
@@ -2263,7 +2514,9 @@ dependencies = [
  "async-std",
  "binary_sv2",
  "buffer_sv2",
+ "clap",
  "codec_sv2",
+ "config",
  "error_handling",
  "framing_sv2",
  "futures",
@@ -2279,7 +2532,6 @@ dependencies = [
  "sv1_api",
  "tokio",
  "tokio-util",
- "toml",
  "tracing",
  "tracing-subscriber",
 ]
@@ -2296,12 +2548,24 @@ version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
+[[package]]
+name = "ucd-trie"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
+[[package]]
+name = "unicode-segmentation"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+
 [[package]]
 name = "universal-hash"
 version = "0.5.1"
@@ -2603,6 +2867,24 @@ version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
+[[package]]
+name = "winnow"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]
+
 [[package]]
 name = "zeroize"
 version = "1.7.0"
diff --git a/roles/jd-client/Cargo.toml b/roles/jd-client/Cargo.toml
index 4c79016d06..08e03bcecd 100644
--- a/roles/jd-client/Cargo.toml
+++ b/roles/jd-client/Cargo.toml
@@ -23,9 +23,10 @@ roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-s
 serde = { version = "1.0.89", default-features = false, features = ["derive", "alloc"] }
 futures = "0.3.25"
 tokio = { version = "1", features = ["full"] }
-toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" }
 tracing = { version = "0.1" }
 tracing-subscriber = { version = "0.3" }
 error_handling = { version = "1.0.0", path = "../../utils/error-handling" }
 nohash-hasher = "0.2.0"
 key-utils = { version = "^1.0.0", path = "../../utils/key-utils" }
+clap = { version = "^4.5.4", features = ["derive"] }
+config = { version = "0.14.0", features = ["toml"] }
\ No newline at end of file
diff --git a/roles/jd-client/src/args.rs b/roles/jd-client/src/args.rs
index 7802351c31..e06d149f61 100644
--- a/roles/jd-client/src/args.rs
+++ b/roles/jd-client/src/args.rs
@@ -1,68 +1,29 @@
-use std::path::PathBuf;
+use crate::lib::{error::JdcResult, jdc_config::JdcConfig};
 
-#[derive(Debug)]
-pub struct Args {
-    pub config_path: PathBuf,
-}
-
-enum ArgsState {
-    Next,
-    ExpectPath,
-    Done,
-}
+use clap::Parser;
 
-enum ArgsResult {
-    Config(PathBuf),
-    None,
-    Help(String),
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+struct Args {
+    #[arg(short, long, help = "Path to TOML configuration file")]
+    config_path: String,
 }
 
-impl Args {
-    const DEFAULT_CONFIG_PATH: &'static str = "jdc-config.toml";
-    const HELP_MSG: &'static str = "Usage: -h/--help, -c/--config <path|default jdc-config.toml>";
-
-    pub fn from_args() -> Result<Self, String> {
-        let cli_args = std::env::args();
-
-        if cli_args.len() == 1 {
-            println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH);
-            println!("{}\n", Self::HELP_MSG);
+#[allow(clippy::result_large_err)]
+pub fn process_cli_args<'a>() -> JdcResult<'a, JdcConfig> {
+    let args = Args::parse();
+    let config = match config::Config::builder()
+        .add_source(config::File::with_name(&args.config_path))
+        .build()
+    {
+        Ok(cfg) => cfg,
+        Err(e) => {
+            tracing::error!("{:?}", e);
+            std::process::exit(1)
         }
+    };
 
-        let config_path = cli_args
-            .scan(ArgsState::Next, |state, item| {
-                match std::mem::replace(state, ArgsState::Done) {
-                    ArgsState::Next => match item.as_str() {
-                        "-c" | "--config" => {
-                            *state = ArgsState::ExpectPath;
-                            Some(ArgsResult::None)
-                        }
-                        "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())),
-                        _ => {
-                            *state = ArgsState::Next;
+    let jdc_config: JdcConfig = config.try_deserialize()?;
 
-                            Some(ArgsResult::None)
-                        }
-                    },
-                    ArgsState::ExpectPath => {
-                        let path = PathBuf::from(item.clone());
-                        if !path.exists() {
-                            return Some(ArgsResult::Help(format!(
-                                "Error: File '{}' does not exist!",
-                                path.display()
-                            )));
-                        }
-                        Some(ArgsResult::Config(path))
-                    }
-                    ArgsState::Done => None,
-                }
-            })
-            .last();
-        let config_path = match config_path {
-            Some(ArgsResult::Config(p)) => p,
-            Some(ArgsResult::Help(h)) => return Err(h),
-            _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH),
-        };
-        Ok(Self { config_path })
-    }
+    Ok(jdc_config)
 }
diff --git a/roles/jd-client/src/lib/error.rs b/roles/jd-client/src/lib/error.rs
index 685137457d..84ea3c5236 100644
--- a/roles/jd-client/src/lib/error.rs
+++ b/roles/jd-client/src/lib/error.rs
@@ -3,7 +3,7 @@ use std::fmt;
 use roles_logic_sv2::mining_sv2::{ExtendedExtranonce, NewExtendedMiningJob, SetCustomMiningJob};
 use stratum_common::bitcoin::util::uint::ParseLengthError;
 
-pub type ProxyResult<'a, T> = core::result::Result<T, Error<'a>>;
+pub type JdcResult<'a, T> = core::result::Result<T, JdcError<'a>>;
 
 #[derive(Debug)]
 pub enum ChannelSendError<'a> {
@@ -26,12 +26,9 @@ pub enum ChannelSendError<'a> {
 }
 
 #[derive(Debug)]
-pub enum Error<'a> {
+pub enum JdcError<'a> {
     VecToSlice32(Vec<u8>),
-    /// Errors on bad CLI argument input.
-    BadCliArgs,
-    /// Errors on bad `toml` deserialize.
-    BadTomlDeserialize(toml::de::Error),
+    ConfigError(config::ConfigError),
     /// Errors from `binary_sv2` crate.
     BinarySv2(binary_sv2::Error),
     /// Errors on bad noise handshake.
@@ -58,12 +55,11 @@ pub enum Error<'a> {
     Infallible(std::convert::Infallible),
 }
 
-impl<'a> fmt::Display for Error<'a> {
+impl<'a> fmt::Display for JdcError<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use Error::*;
+        use JdcError::*;
         match self {
-            BadCliArgs => write!(f, "Bad CLI arg input"),
-            BadTomlDeserialize(ref e) => write!(f, "Bad `toml` deserialize: `{:?}`", e),
+            ConfigError(e) => write!(f, "Config error: {:?}", e),
             BinarySv2(ref e) => write!(f, "Binary SV2 error: `{:?}`", e),
             CodecNoise(ref e) => write!(f, "Noise error: `{:?}", e),
             FramingSv2(ref e) => write!(f, "Framing SV2 error: `{:?}`", e),
@@ -83,57 +79,57 @@ impl<'a> fmt::Display for Error<'a> {
     }
 }
 
-impl<'a> From<binary_sv2::Error> for Error<'a> {
+impl<'a> From<config::ConfigError> for JdcError<'a> {
+    fn from(e: config::ConfigError) -> JdcError<'a> {
+        JdcError::ConfigError(e)
+    }
+}
+
+impl<'a> From<binary_sv2::Error> for JdcError<'a> {
     fn from(e: binary_sv2::Error) -> Self {
-        Error::BinarySv2(e)
+        JdcError::BinarySv2(e)
     }
 }
 
-impl<'a> From<codec_sv2::noise_sv2::Error> for Error<'a> {
+impl<'a> From<codec_sv2::noise_sv2::Error> for JdcError<'a> {
     fn from(e: codec_sv2::noise_sv2::Error) -> Self {
-        Error::CodecNoise(e)
+        JdcError::CodecNoise(e)
     }
 }
 
-impl<'a> From<framing_sv2::Error> for Error<'a> {
+impl<'a> From<framing_sv2::Error> for JdcError<'a> {
     fn from(e: framing_sv2::Error) -> Self {
-        Error::FramingSv2(e)
+        JdcError::FramingSv2(e)
     }
 }
 
-impl<'a> From<std::io::Error> for Error<'a> {
+impl<'a> From<std::io::Error> for JdcError<'a> {
     fn from(e: std::io::Error) -> Self {
-        Error::Io(e)
+        JdcError::Io(e)
     }
 }
 
-impl<'a> From<std::num::ParseIntError> for Error<'a> {
+impl<'a> From<std::num::ParseIntError> for JdcError<'a> {
     fn from(e: std::num::ParseIntError) -> Self {
-        Error::ParseInt(e)
+        JdcError::ParseInt(e)
     }
 }
 
-impl<'a> From<roles_logic_sv2::errors::Error> for Error<'a> {
+impl<'a> From<roles_logic_sv2::errors::Error> for JdcError<'a> {
     fn from(e: roles_logic_sv2::errors::Error) -> Self {
-        Error::RolesSv2Logic(e)
-    }
-}
-
-impl<'a> From<toml::de::Error> for Error<'a> {
-    fn from(e: toml::de::Error) -> Self {
-        Error::BadTomlDeserialize(e)
+        JdcError::RolesSv2Logic(e)
     }
 }
 
-impl<'a> From<async_channel::RecvError> for Error<'a> {
+impl<'a> From<async_channel::RecvError> for JdcError<'a> {
     fn from(e: async_channel::RecvError) -> Self {
-        Error::ChannelErrorReceiver(e)
+        JdcError::ChannelErrorReceiver(e)
     }
 }
 
-impl<'a> From<tokio::sync::broadcast::error::RecvError> for Error<'a> {
+impl<'a> From<tokio::sync::broadcast::error::RecvError> for JdcError<'a> {
     fn from(e: tokio::sync::broadcast::error::RecvError) -> Self {
-        Error::TokioChannelErrorRecv(e)
+        JdcError::TokioChannelErrorRecv(e)
     }
 }
 
@@ -156,38 +152,38 @@ impl<'a> From<tokio::sync::broadcast::error::RecvError> for Error<'a> {
 
 // *** CHANNEL SENDER ERRORS ***
 impl<'a> From<async_channel::SendError<roles_logic_sv2::mining_sv2::SubmitSharesExtended<'a>>>
-    for Error<'a>
+    for JdcError<'a>
 {
     fn from(
         e: async_channel::SendError<roles_logic_sv2::mining_sv2::SubmitSharesExtended<'a>>,
     ) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e))
+        JdcError::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e))
     }
 }
 
 impl<'a> From<async_channel::SendError<roles_logic_sv2::mining_sv2::SetNewPrevHash<'a>>>
-    for Error<'a>
+    for JdcError<'a>
 {
     fn from(e: async_channel::SendError<roles_logic_sv2::mining_sv2::SetNewPrevHash<'a>>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e))
+        JdcError::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e))
     }
 }
 
-impl<'a> From<async_channel::SendError<(ExtendedExtranonce, u32)>> for Error<'a> {
+impl<'a> From<async_channel::SendError<(ExtendedExtranonce, u32)>> for JdcError<'a> {
     fn from(e: async_channel::SendError<(ExtendedExtranonce, u32)>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::Extranonce(e))
+        JdcError::ChannelErrorSender(ChannelSendError::Extranonce(e))
     }
 }
 
-impl<'a> From<async_channel::SendError<NewExtendedMiningJob<'a>>> for Error<'a> {
+impl<'a> From<async_channel::SendError<NewExtendedMiningJob<'a>>> for JdcError<'a> {
     fn from(e: async_channel::SendError<NewExtendedMiningJob<'a>>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e))
+        JdcError::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e))
     }
 }
 
-impl<'a> From<async_channel::SendError<SetCustomMiningJob<'a>>> for Error<'a> {
+impl<'a> From<async_channel::SendError<SetCustomMiningJob<'a>>> for JdcError<'a> {
     fn from(e: async_channel::SendError<SetCustomMiningJob<'a>>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e))
+        JdcError::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e))
     }
 }
 
@@ -197,7 +193,7 @@ impl<'a>
             roles_logic_sv2::template_distribution_sv2::SetNewPrevHash<'a>,
             Vec<u8>,
         )>,
-    > for Error<'a>
+    > for JdcError<'a>
 {
     fn from(
         e: async_channel::SendError<(
@@ -205,24 +201,24 @@ impl<'a>
             Vec<u8>,
         )>,
     ) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::NewTemplate(e))
+        JdcError::ChannelErrorSender(ChannelSendError::NewTemplate(e))
     }
 }
 
-impl<'a> From<Vec<u8>> for Error<'a> {
+impl<'a> From<Vec<u8>> for JdcError<'a> {
     fn from(e: Vec<u8>) -> Self {
-        Error::VecToSlice32(e)
+        JdcError::VecToSlice32(e)
     }
 }
 
-impl<'a> From<ParseLengthError> for Error<'a> {
+impl<'a> From<ParseLengthError> for JdcError<'a> {
     fn from(e: ParseLengthError) -> Self {
-        Error::Uint256Conversion(e)
+        JdcError::Uint256Conversion(e)
     }
 }
 
-impl<'a> From<std::convert::Infallible> for Error<'a> {
+impl<'a> From<std::convert::Infallible> for JdcError<'a> {
     fn from(e: std::convert::Infallible) -> Self {
-        Error::Infallible(e)
+        JdcError::Infallible(e)
     }
 }
diff --git a/roles/jd-client/src/lib/proxy_config.rs b/roles/jd-client/src/lib/jdc_config.rs
similarity index 97%
rename from roles/jd-client/src/lib/proxy_config.rs
rename to roles/jd-client/src/lib/jdc_config.rs
index 89c97a7beb..98be0f2439 100644
--- a/roles/jd-client/src/lib/proxy_config.rs
+++ b/roles/jd-client/src/lib/jdc_config.rs
@@ -25,7 +25,7 @@ impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ {
 }
 
 #[derive(Debug, Deserialize, Clone)]
-pub struct ProxyConfig {
+pub struct JdcConfig {
     pub downstream_address: String,
     pub downstream_port: u16,
     pub max_supported_version: u16,
@@ -82,7 +82,7 @@ where
     }
 }
 
-pub fn get_coinbase_output(config: &ProxyConfig) -> Result<Vec<TxOut>, Error> {
+pub fn get_coinbase_output(config: &JdcConfig) -> Result<Vec<TxOut>, Error> {
     let mut result = Vec::new();
     for coinbase_output_pool in &config.coinbase_outputs {
         let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?;
diff --git a/roles/jd-client/src/lib/job_declarator/mod.rs b/roles/jd-client/src/lib/job_declarator/mod.rs
index abaf852ca2..bc6fb856ba 100644
--- a/roles/jd-client/src/lib/job_declarator/mod.rs
+++ b/roles/jd-client/src/lib/job_declarator/mod.rs
@@ -37,7 +37,7 @@ pub type StdFrame = StandardSv2Frame<Message>;
 mod setup_connection;
 use setup_connection::SetupConnectionHandler;
 
-use super::{error::Error, proxy_config::ProxyConfig, upstream_sv2::Upstream};
+use super::{error::JdcError, jdc_config::JdcConfig, upstream_sv2::Upstream};
 
 #[derive(Debug, Clone)]
 pub struct LastDeclareJob {
@@ -80,10 +80,10 @@ impl JobDeclarator {
     pub async fn new(
         address: SocketAddr,
         authority_public_key: [u8; 32],
-        config: ProxyConfig,
+        config: JdcConfig,
         up: Arc<Mutex<Upstream>>,
         task_collector: Arc<Mutex<Vec<AbortHandle>>>,
-    ) -> Result<Arc<Mutex<Self>>, Error<'static>> {
+    ) -> Result<Arc<Mutex<Self>>, JdcError<'static>> {
         let stream = tokio::net::TcpStream::connect(address).await?;
         let initiator = Initiator::from_raw_k(authority_public_key)?;
         let (mut receiver, mut sender, _, _) =
diff --git a/roles/jd-client/src/lib/mod.rs b/roles/jd-client/src/lib/mod.rs
index 489759420e..5828fab6f8 100644
--- a/roles/jd-client/src/lib/mod.rs
+++ b/roles/jd-client/src/lib/mod.rs
@@ -1,7 +1,7 @@
 pub mod downstream;
 pub mod error;
+pub mod jdc_config;
 pub mod job_declarator;
-pub mod proxy_config;
 pub mod status;
 pub mod template_receiver;
 pub mod upstream_sv2;
diff --git a/roles/jd-client/src/lib/status.rs b/roles/jd-client/src/lib/status.rs
index 44e6056d26..f94af5c764 100644
--- a/roles/jd-client/src/lib/status.rs
+++ b/roles/jd-client/src/lib/status.rs
@@ -1,4 +1,4 @@
-use super::error::{self, Error};
+use super::error::{self, JdcError};
 
 #[derive(Debug)]
 pub enum Sender {
@@ -35,8 +35,8 @@ impl Clone for Sender {
 
 #[derive(Debug)]
 pub enum State<'a> {
-    DownstreamShutdown(Error<'a>),
-    UpstreamShutdown(Error<'a>),
+    DownstreamShutdown(JdcError<'a>),
+    UpstreamShutdown(JdcError<'a>),
     UpstreamRogue,
     Healthy(String),
 }
@@ -48,7 +48,7 @@ pub struct Status<'a> {
 
 async fn send_status(
     sender: &Sender,
-    e: error::Error<'static>,
+    e: error::JdcError<'static>,
     outcome: error_handling::ErrorBranch,
 ) -> error_handling::ErrorBranch {
     match sender {
@@ -87,51 +87,52 @@ async fn send_status(
 // this is called by `error_handling::handle_result!`
 pub async fn handle_error(
     sender: &Sender,
-    e: error::Error<'static>,
+    e: error::JdcError<'static>,
 ) -> error_handling::ErrorBranch {
     tracing::error!("Error: {:?}", &e);
     match e {
-        Error::VecToSlice32(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
-        // Errors on bad CLI argument input.
-        Error::BadCliArgs => send_status(sender, e, error_handling::ErrorBranch::Break).await,
-        // Errors on bad `toml` deserialize.
-        Error::BadTomlDeserialize(_) => {
+        JdcError::VecToSlice32(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
+        JdcError::ConfigError(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // Errors from `binary_sv2` crate.
-        Error::BinarySv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        JdcError::BinarySv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Errors on bad noise handshake.
-        Error::CodecNoise(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        JdcError::CodecNoise(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Errors from `framing_sv2` crate.
-        Error::FramingSv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        JdcError::FramingSv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Errors on bad `TcpStream` connection.
-        Error::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        JdcError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Errors on bad `String` to `int` conversion.
-        Error::ParseInt(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        JdcError::ParseInt(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Errors from `roles_logic_sv2` crate.
-        Error::RolesSv2Logic(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
-        Error::UpstreamIncoming(_) => {
+        JdcError::RolesSv2Logic(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
+        JdcError::UpstreamIncoming(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::SubprotocolMining(_) => {
+        JdcError::SubprotocolMining(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // Locking Errors
-        Error::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        JdcError::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Channel Receiver Error
-        Error::ChannelErrorReceiver(_) => {
+        JdcError::ChannelErrorReceiver(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::TokioChannelErrorRecv(_) => {
+        JdcError::TokioChannelErrorRecv(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // Channel Sender Errors
-        Error::ChannelErrorSender(_) => {
+        JdcError::ChannelErrorSender(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::Uint256Conversion(_) => {
+        JdcError::Uint256Conversion(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::Infallible(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        JdcError::Infallible(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
     }
 }
diff --git a/roles/jd-client/src/lib/upstream_sv2/upstream.rs b/roles/jd-client/src/lib/upstream_sv2/upstream.rs
index 857cbd3087..dd471b7851 100644
--- a/roles/jd-client/src/lib/upstream_sv2/upstream.rs
+++ b/roles/jd-client/src/lib/upstream_sv2/upstream.rs
@@ -2,8 +2,8 @@ use super::super::downstream::DownstreamMiningNode as Downstream;
 
 use super::super::{
     error::{
-        Error::{CodecNoise, PoisonLock, UpstreamIncoming},
-        ProxyResult,
+        JdcError::{CodecNoise, PoisonLock, UpstreamIncoming},
+        JdcResult,
     },
     status,
     upstream_sv2::{EitherFrame, Message, StdFrame},
@@ -127,13 +127,13 @@ pub struct Upstream {
 }
 
 impl Upstream {
-    pub async fn send(self_: &Arc<Mutex<Self>>, sv2_frame: StdFrame) -> ProxyResult<'static, ()> {
+    pub async fn send(self_: &Arc<Mutex<Self>>, sv2_frame: StdFrame) -> JdcResult<'static, ()> {
         let sender = self_
             .safe_lock(|s| s.sender.clone())
             .map_err(|_| PoisonLock)?;
         let either_frame = sv2_frame.into();
         sender.send(either_frame).await.map_err(|e| {
-            super::super::error::Error::ChannelErrorSender(
+            super::super::error::JdcError::ChannelErrorSender(
                 super::super::error::ChannelSendError::General(e.to_string()),
             )
         })?;
@@ -153,7 +153,7 @@ impl Upstream {
         tx_status: status::Sender,
         task_collector: Arc<Mutex<Vec<AbortHandle>>>,
         pool_chaneger_trigger: Arc<Mutex<PoolChangerTrigger>>,
-    ) -> ProxyResult<'static, Arc<Mutex<Self>>> {
+    ) -> JdcResult<'static, Arc<Mutex<Self>>> {
         // Connect to the SV2 Upstream role retry connection every 5 seconds.
         let socket = loop {
             match TcpStream::connect(address).await {
@@ -204,7 +204,7 @@ impl Upstream {
         self_: Arc<Mutex<Self>>,
         min_version: u16,
         max_version: u16,
-    ) -> ProxyResult<'static, ()> {
+    ) -> JdcResult<'static, ()> {
         // Get the `SetupConnection` message with Mining Device information (currently hard coded)
         let setup_connection = Self::get_setup_connection_message(min_version, max_version, true)?;
 
@@ -264,7 +264,7 @@ impl Upstream {
         coinbase_tx_outs: Vec<u8>,
         coinbase_tx_locktime: u32,
         template_id: u64,
-    ) -> ProxyResult<'static, ()> {
+    ) -> JdcResult<'static, ()> {
         info!("Sending set custom mining job");
         let request_id = self_.safe_lock(|s| s.req_ids.next()).unwrap();
         let channel_id = loop {
@@ -310,7 +310,7 @@ impl Upstream {
     /// Parses the incoming SV2 message from the Upstream role and routes the message to the
     /// appropriate handler.
     #[allow(clippy::result_large_err)]
-    pub fn parse_incoming(self_: Arc<Mutex<Self>>) -> ProxyResult<'static, ()> {
+    pub fn parse_incoming(self_: Arc<Mutex<Self>>) -> JdcResult<'static, ()> {
         let (recv, tx_status) = self_
             .safe_lock(|s| (s.receiver.clone(), s.tx_status.clone()))
             .map_err(|_| PoisonLock)?;
@@ -327,7 +327,7 @@ impl Upstream {
                     let message_type =
                         incoming
                             .get_header()
-                            .ok_or(super::super::error::Error::FramingSv2(
+                            .ok_or(super::super::error::JdcError::FramingSv2(
                                 framing_sv2::Error::ExpectedSv2Frame,
                             ));
 
@@ -404,7 +404,7 @@ impl Upstream {
         min_version: u16,
         max_version: u16,
         is_work_selection_enabled: bool,
-    ) -> ProxyResult<'static, SetupConnection<'static>> {
+    ) -> JdcResult<'static, SetupConnection<'static>> {
         let endpoint_host = "0.0.0.0".to_string().into_bytes().try_into()?;
         let vendor = String::new().try_into()?;
         let hardware_version = String::new().try_into()?;
diff --git a/roles/jd-client/src/main.rs b/roles/jd-client/src/main.rs
index ac246987ed..b21788666f 100644
--- a/roles/jd-client/src/main.rs
+++ b/roles/jd-client/src/main.rs
@@ -4,15 +4,9 @@ mod args;
 mod lib;
 
 use lib::{
-    error::{Error, ProxyResult},
-    job_declarator::JobDeclarator,
-    proxy_config::ProxyConfig,
-    status,
-    template_receiver::TemplateRx,
-    PoolChangerTrigger,
+    job_declarator::JobDeclarator, status, template_receiver::TemplateRx, PoolChangerTrigger,
 };
 
-use args::Args;
 use async_channel::{bounded, unbounded};
 use futures::{select, FutureExt};
 use roles_logic_sv2::utils::Mutex;
@@ -26,20 +20,6 @@ use tokio::task::AbortHandle;
 
 use tracing::{error, info};
 
-/// Process CLI args, if any.
-#[allow(clippy::result_large_err)]
-fn process_cli_args<'a>() -> ProxyResult<'a, ProxyConfig> {
-    let args = match Args::from_args() {
-        Ok(cfg) => cfg,
-        Err(help) => {
-            error!("{}", help);
-            return Err(Error::BadCliArgs);
-        }
-    };
-    let config_file = std::fs::read_to_string(args.config_path)?;
-    Ok(toml::from_str::<ProxyConfig>(&config_file)?)
-}
-
 /// TODO on the setup phase JDC must send a random nonce to bitcoind and JDS used for the tx
 /// hashlist
 ///
@@ -105,7 +85,7 @@ async fn main() {
 
     let task_collector = Arc::new(Mutex::new(vec![]));
 
-    let proxy_config = match process_cli_args() {
+    let jdc_config = match args::process_cli_args() {
         Ok(p) => p,
         Err(_) => return,
     };
@@ -115,19 +95,19 @@ async fn main() {
             let task_collector = task_collector.clone();
             let tx_status = tx_status.clone();
 
-            if let Some(upstream) = proxy_config.upstreams.get(upstream_index) {
+            if let Some(upstream) = jdc_config.upstreams.get(upstream_index) {
                 let initialize = initialize_jd(
                     tx_status.clone(),
                     task_collector,
                     upstream.clone(),
-                    proxy_config.timeout,
+                    jdc_config.timeout,
                 );
                 tokio::task::spawn(initialize);
             } else {
                 let initialize = initialize_jd_as_solo_miner(
                     tx_status.clone(),
                     task_collector,
-                    proxy_config.timeout,
+                    jdc_config.timeout,
                 );
                 tokio::task::spawn(initialize);
             }
@@ -205,8 +185,8 @@ async fn initialize_jd_as_solo_miner(
     task_collector: Arc<Mutex<Vec<AbortHandle>>>,
     timeout: Duration,
 ) {
-    let proxy_config = process_cli_args().unwrap();
-    let miner_tx_out = lib::proxy_config::get_coinbase_output(&proxy_config).unwrap();
+    let proxy_config = args::process_cli_args().unwrap();
+    let miner_tx_out = lib::jdc_config::get_coinbase_output(&proxy_config).unwrap();
 
     // When Downstream receive a share that meets bitcoin target it transformit in a
     // SubmitSolution and send it to the TemplateReceiver
@@ -258,11 +238,11 @@ async fn initialize_jd_as_solo_miner(
 async fn initialize_jd(
     tx_status: async_channel::Sender<status::Status<'static>>,
     task_collector: Arc<Mutex<Vec<AbortHandle>>>,
-    upstream_config: lib::proxy_config::Upstream,
+    upstream_config: lib::jdc_config::Upstream,
     timeout: Duration,
 ) {
-    let proxy_config = process_cli_args().unwrap();
-    let test_only_do_not_send_solution_to_tp = proxy_config
+    let jdc_config = args::process_cli_args().unwrap();
+    let test_only_do_not_send_solution_to_tp = jdc_config
         .test_only_do_not_send_solution_to_tp
         .unwrap_or(false);
 
@@ -312,8 +292,8 @@ async fn initialize_jd(
 
     match lib::upstream_sv2::Upstream::setup_connection(
         upstream.clone(),
-        proxy_config.min_supported_version,
-        proxy_config.max_supported_version,
+        jdc_config.min_supported_version,
+        jdc_config.max_supported_version,
     )
     .await
     {
@@ -326,12 +306,12 @@ async fn initialize_jd(
 
     // Format `Downstream` connection address
     let downstream_addr = SocketAddr::new(
-        IpAddr::from_str(&proxy_config.downstream_address).unwrap(),
-        proxy_config.downstream_port,
+        IpAddr::from_str(&jdc_config.downstream_address).unwrap(),
+        jdc_config.downstream_port,
     );
 
     // Initialize JD part
-    let mut parts = proxy_config.tp_address.split(':');
+    let mut parts = jdc_config.tp_address.split(':');
     let ip_tp = parts.next().unwrap().to_string();
     let port_tp = parts.next().unwrap().parse::<u16>().unwrap();
 
@@ -341,7 +321,7 @@ async fn initialize_jd(
     let jd = match JobDeclarator::new(
         SocketAddr::new(IpAddr::from_str(ip_jd.as_str()).unwrap(), port_jd),
         upstream_config.authority_pubkey.into_bytes(),
-        proxy_config.clone(),
+        jdc_config.clone(),
         upstream.clone(),
         task_collector.clone(),
     )
@@ -363,10 +343,10 @@ async fn initialize_jd(
         downstream_addr,
         Some(upstream),
         send_solution,
-        proxy_config.withhold,
-        proxy_config.authority_public_key,
-        proxy_config.authority_secret_key,
-        proxy_config.cert_validity_sec,
+        jdc_config.withhold,
+        jdc_config.authority_public_key,
+        jdc_config.authority_secret_key,
+        jdc_config.cert_validity_sec,
         task_collector.clone(),
         status::Sender::Downstream(tx_status.clone()),
         vec![],
@@ -384,7 +364,7 @@ async fn initialize_jd(
         task_collector,
         Arc::new(Mutex::new(PoolChangerTrigger::new(timeout))),
         vec![],
-        proxy_config.tp_authority_public_key,
+        jdc_config.tp_authority_public_key,
         test_only_do_not_send_solution_to_tp,
     )
     .await;
diff --git a/roles/jd-server/Cargo.toml b/roles/jd-server/Cargo.toml
index 6f55ece068..6d344cc9d1 100644
--- a/roles/jd-server/Cargo.toml
+++ b/roles/jd-server/Cargo.toml
@@ -21,7 +21,6 @@ noise_sv2 = { version = "1.1.0", path = "../../protocols/v2/noise-sv2" }
 rand = "0.8.4"
 roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" }
 tokio = { version = "1", features = ["full"] }
-toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" }
 tracing = { version = "0.1" }
 tracing-subscriber = "0.3"
 error_handling = { version = "1.0.0", path = "../../utils/error-handling" }
@@ -32,3 +31,5 @@ hashbrown = { version = "0.11", default-features = false, features = ["ahash", "
 key-utils = { version = "^1.0.0", path = "../../utils/key-utils" }
 rpc_sv2 = { version = "1.0.0", path = "../roles-utils/rpc" }
 hex = "0.4.3"
+clap = { version = "^4.5.4", features = ["derive"] }
+config = { version = "0.14.0", features = ["toml"] }
\ No newline at end of file
diff --git a/roles/jd-server/src/args.rs b/roles/jd-server/src/args.rs
new file mode 100644
index 0000000000..b7bc68bfe8
--- /dev/null
+++ b/roles/jd-server/src/args.rs
@@ -0,0 +1,28 @@
+use crate::lib::{error::JdsResult, jds_config::JdsConfig};
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+struct Args {
+    #[arg(short, long, help = "Path to TOML configuration file")]
+    config_path: String,
+}
+
+#[allow(clippy::result_large_err)]
+pub fn process_cli_args() -> JdsResult<JdsConfig> {
+    let args = Args::parse();
+    let config = match config::Config::builder()
+        .add_source(config::File::with_name(&args.config_path))
+        .build()
+    {
+        Ok(cfg) => cfg,
+        Err(e) => {
+            tracing::error!("{:?}", e);
+            std::process::exit(1)
+        }
+    };
+
+    let jds_config: JdsConfig = config.try_deserialize()?;
+
+    Ok(jds_config)
+}
diff --git a/roles/jd-server/src/lib/error.rs b/roles/jd-server/src/lib/error.rs
index 7b58c75939..265807def7 100644
--- a/roles/jd-server/src/lib/error.rs
+++ b/roles/jd-server/src/lib/error.rs
@@ -8,8 +8,11 @@ use roles_logic_sv2::parsers::Mining;
 
 use crate::mempool::error::JdsMempoolError;
 
+pub type JdsResult<T> = core::result::Result<T, JdsError>;
+
 #[derive(std::fmt::Debug)]
 pub enum JdsError {
+    ConfigError(config::ConfigError),
     Io(std::io::Error),
     ChannelSend(Box<dyn std::marker::Send + Debug>),
     ChannelRecv(async_channel::RecvError),
@@ -30,6 +33,7 @@ impl std::fmt::Display for JdsError {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         use JdsError::*;
         match self {
+            ConfigError(e) => write!(f, "Config error: {:?}", e),
             Io(ref e) => write!(f, "I/O error: `{:?}", e),
             ChannelSend(ref e) => write!(f, "Channel send failed: `{:?}`", e),
             ChannelRecv(ref e) => write!(f, "Channel recv failed: `{:?}`", e),
@@ -52,6 +56,12 @@ impl std::fmt::Display for JdsError {
     }
 }
 
+impl From<config::ConfigError> for JdsError {
+    fn from(e: config::ConfigError) -> JdsError {
+        JdsError::ConfigError(e)
+    }
+}
+
 impl From<std::io::Error> for JdsError {
     fn from(e: std::io::Error) -> JdsError {
         JdsError::Io(e)
diff --git a/roles/jd-server/src/lib/jds_config.rs b/roles/jd-server/src/lib/jds_config.rs
new file mode 100644
index 0000000000..f2adb9b0bc
--- /dev/null
+++ b/roles/jd-server/src/lib/jds_config.rs
@@ -0,0 +1,88 @@
+use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey};
+use roles_logic_sv2::{errors::Error, utils::CoinbaseOutput as CoinbaseOutput_};
+use serde::Deserialize;
+use std::{
+    convert::{TryFrom, TryInto},
+    time::Duration,
+};
+use stratum_common::bitcoin::{Script, TxOut};
+
+pub fn get_coinbase_output(config: &JdsConfig) -> Result<Vec<TxOut>, Error> {
+    let mut result = Vec::new();
+    for coinbase_output_pool in &config.coinbase_outputs {
+        let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?;
+        let output_script: Script = coinbase_output.try_into()?;
+        result.push(TxOut {
+            value: 0,
+            script_pubkey: output_script,
+        });
+    }
+    match result.is_empty() {
+        true => Err(Error::EmptyCoinbaseOutputs),
+        _ => Ok(result),
+    }
+}
+
+impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ {
+    type Error = Error;
+
+    fn try_from(pool_output: &CoinbaseOutput) -> Result<Self, Self::Error> {
+        match pool_output.output_script_type.as_str() {
+            "P2PK" | "P2PKH" | "P2WPKH" | "P2SH" | "P2WSH" | "P2TR" => Ok(CoinbaseOutput_ {
+                output_script_type: pool_output.clone().output_script_type,
+                output_script_value: pool_output.clone().output_script_value,
+            }),
+            _ => Err(Error::UnknownOutputScriptType),
+        }
+    }
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct CoinbaseOutput {
+    output_script_type: String,
+    output_script_value: String,
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct JdsConfig {
+    pub listen_jd_address: String,
+    pub authority_public_key: Secp256k1PublicKey,
+    pub authority_secret_key: Secp256k1SecretKey,
+    pub cert_validity_sec: u64,
+    pub coinbase_outputs: Vec<CoinbaseOutput>,
+    pub core_rpc_url: String,
+    pub core_rpc_port: u16,
+    pub core_rpc_user: String,
+    pub core_rpc_pass: String,
+    #[serde(deserialize_with = "duration_from_toml")]
+    pub mempool_update_interval: Duration,
+}
+
+fn duration_from_toml<'de, D>(deserializer: D) -> Result<Duration, D::Error>
+where
+    D: serde::Deserializer<'de>,
+{
+    #[derive(Deserialize)]
+    struct Helper {
+        unit: String,
+        value: u64,
+    }
+
+    let helper = Helper::deserialize(deserializer)?;
+    match helper.unit.as_str() {
+        "seconds" => Ok(Duration::from_secs(helper.value)),
+        "secs" => Ok(Duration::from_secs(helper.value)),
+        "s" => Ok(Duration::from_secs(helper.value)),
+        "milliseconds" => Ok(Duration::from_millis(helper.value)),
+        "millis" => Ok(Duration::from_millis(helper.value)),
+        "ms" => Ok(Duration::from_millis(helper.value)),
+        "microseconds" => Ok(Duration::from_micros(helper.value)),
+        "micros" => Ok(Duration::from_micros(helper.value)),
+        "us" => Ok(Duration::from_micros(helper.value)),
+        "nanoseconds" => Ok(Duration::from_nanos(helper.value)),
+        "nanos" => Ok(Duration::from_nanos(helper.value)),
+        "ns" => Ok(Duration::from_nanos(helper.value)),
+        // ... add other units as needed
+        _ => Err(serde::de::Error::custom("Unsupported duration unit")),
+    }
+}
diff --git a/roles/jd-server/src/lib/job_declarator/mod.rs b/roles/jd-server/src/lib/job_declarator/mod.rs
index 56d56223cc..c56a1c1119 100644
--- a/roles/jd-server/src/lib/job_declarator/mod.rs
+++ b/roles/jd-server/src/lib/job_declarator/mod.rs
@@ -1,5 +1,7 @@
 pub mod message_handler;
-use super::{error::JdsError, mempool::JDsMempool, status, Configuration, EitherFrame, StdFrame};
+use super::{
+    error::JdsError, jds_config::JdsConfig, mempool::JDsMempool, status, EitherFrame, StdFrame,
+};
 use async_channel::{Receiver, Sender};
 use binary_sv2::{B0255, U256};
 use codec_sv2::{Frame, HandshakeRole, Responder};
@@ -69,7 +71,7 @@ impl JobDeclaratorDownstream {
     pub fn new(
         receiver: Receiver<EitherFrame>,
         sender: Sender<EitherFrame>,
-        config: &Configuration,
+        config: &JdsConfig,
         mempool: Arc<Mutex<JDsMempool>>,
         sender_add_txs_to_mempool: Sender<AddTrasactionsToMempoolInner>,
     ) -> Self {
@@ -81,9 +83,10 @@ impl JobDeclaratorDownstream {
             known_transactions: vec![],
             unknown_transactions: vec![],
         };
-        super::get_coinbase_output(config).expect("Invalid coinbase output in config")[0]
-            .consensus_encode(&mut coinbase_output)
-            .expect("Invalid coinbase output in config");
+        super::jds_config::get_coinbase_output(config).expect("Invalid coinbase output in config")
+            [0]
+        .consensus_encode(&mut coinbase_output)
+        .expect("Invalid coinbase output in config");
 
         Self {
             receiver,
@@ -411,7 +414,7 @@ pub struct JobDeclarator {}
 
 impl JobDeclarator {
     pub async fn start(
-        config: Configuration,
+        config: JdsConfig,
         status_tx: crate::status::Sender,
         mempool: Arc<Mutex<JDsMempool>>,
         new_block_sender: Sender<String>,
@@ -431,7 +434,7 @@ impl JobDeclarator {
     }
     async fn accept_incoming_connection(
         _self_: Arc<Mutex<JobDeclarator>>,
-        config: Configuration,
+        config: JdsConfig,
         status_tx: crate::status::Sender,
         mempool: Arc<Mutex<JDsMempool>>,
         new_block_sender: Sender<String>,
diff --git a/roles/jd-server/src/lib/mod.rs b/roles/jd-server/src/lib/mod.rs
index a76c80cf1f..a679195fe9 100644
--- a/roles/jd-server/src/lib/mod.rs
+++ b/roles/jd-server/src/lib/mod.rs
@@ -1,4 +1,5 @@
 pub mod error;
+pub mod jds_config;
 pub mod job_declarator;
 pub mod mempool;
 pub mod status;
@@ -9,32 +10,12 @@ use roles_logic_sv2::{
     errors::Error, parsers::PoolMessages as JdsMessages, utils::CoinbaseOutput as CoinbaseOutput_,
 };
 use serde::Deserialize;
-use std::{
-    convert::{TryFrom, TryInto},
-    time::Duration,
-};
-use stratum_common::bitcoin::{Script, TxOut};
+use std::{convert::TryFrom, time::Duration};
 
 pub type Message = JdsMessages<'static>;
 pub type StdFrame = StandardSv2Frame<Message>;
 pub type EitherFrame = StandardEitherFrame<Message>;
 
-pub fn get_coinbase_output(config: &Configuration) -> Result<Vec<TxOut>, Error> {
-    let mut result = Vec::new();
-    for coinbase_output_pool in &config.coinbase_outputs {
-        let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?;
-        let output_script: Script = coinbase_output.try_into()?;
-        result.push(TxOut {
-            value: 0,
-            script_pubkey: output_script,
-        });
-    }
-    match result.is_empty() {
-        true => Err(Error::EmptyCoinbaseOutputs),
-        _ => Ok(result),
-    }
-}
-
 impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ {
     type Error = Error;
 
diff --git a/roles/jd-server/src/lib/status.rs b/roles/jd-server/src/lib/status.rs
index 83a50026ff..e76d7bbcd3 100644
--- a/roles/jd-server/src/lib/status.rs
+++ b/roles/jd-server/src/lib/status.rs
@@ -98,6 +98,9 @@ async fn send_status(
 pub async fn handle_error(sender: &Sender, e: JdsError) -> error_handling::ErrorBranch {
     tracing::debug!("Error: {:?}", &e);
     match e {
+        JdsError::ConfigError(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
         JdsError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         JdsError::ChannelSend(_) => {
             //This should be a continue because if we fail to send to 1 downstream we should continue
diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs
index 9d56b491f7..f22874c7d7 100644
--- a/roles/jd-server/src/main.rs
+++ b/roles/jd-server/src/main.rs
@@ -1,7 +1,7 @@
 #![allow(special_module_name)]
 use crate::lib::{
     mempool::{self, error::JdsMempoolError},
-    status, Configuration,
+    status,
 };
 use async_channel::{bounded, unbounded, Receiver, Sender};
 use error_handling::handle_result;
@@ -9,102 +9,22 @@ use roles_logic_sv2::utils::Mutex;
 use std::{ops::Sub, sync::Arc};
 use tokio::{select, task};
 use tracing::{error, info, warn};
+mod args;
 mod lib;
 
 use lib::job_declarator::JobDeclarator;
 
-mod args {
-    use std::path::PathBuf;
-
-    #[derive(Debug)]
-    pub struct Args {
-        pub config_path: PathBuf,
-    }
-
-    enum ArgsState {
-        Next,
-        ExpectPath,
-        Done,
-    }
-
-    enum ArgsResult {
-        Config(PathBuf),
-        None,
-        Help(String),
-    }
-
-    impl Args {
-        const DEFAULT_CONFIG_PATH: &'static str = "jds-config.toml";
-        const HELP_MSG: &'static str =
-            "Usage: -h/--help, -c/--config <path|default jds-config.toml>";
-
-        pub fn from_args() -> Result<Self, String> {
-            let cli_args = std::env::args();
-
-            if cli_args.len() == 1 {
-                println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH);
-                println!("{}\n", Self::HELP_MSG);
-            }
-
-            let config_path = cli_args
-                .scan(ArgsState::Next, |state, item| {
-                    match std::mem::replace(state, ArgsState::Done) {
-                        ArgsState::Next => match item.as_str() {
-                            "-c" | "--config" => {
-                                *state = ArgsState::ExpectPath;
-                                Some(ArgsResult::None)
-                            }
-                            "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())),
-                            _ => {
-                                *state = ArgsState::Next;
-
-                                Some(ArgsResult::None)
-                            }
-                        },
-                        ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))),
-                        ArgsState::Done => None,
-                    }
-                })
-                .last();
-            let config_path = match config_path {
-                Some(ArgsResult::Config(p)) => p,
-                Some(ArgsResult::Help(h)) => return Err(h),
-                _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH),
-            };
-            Ok(Self { config_path })
-        }
-    }
-}
-
 #[tokio::main]
 async fn main() {
     tracing_subscriber::fmt::init();
-    let args = match args::Args::from_args() {
-        Ok(cfg) => cfg,
-        Err(help) => {
-            error!("{}", help);
-            return;
-        }
-    };
-
-    // Load config
-    let config: Configuration = match std::fs::read_to_string(&args.config_path) {
-        Ok(c) => match toml::from_str(&c) {
-            Ok(c) => c,
-            Err(e) => {
-                error!("Failed to parse config: {}", e);
-                return;
-            }
-        },
-        Err(e) => {
-            error!("Failed to read config: {}", e);
-            return;
-        }
+    let jds_config = match args::process_cli_args() {
+        Ok(p) => p,
+        Err(_) => return,
     };
 
-    let url = config.core_rpc_url.clone() + ":" + &config.core_rpc_port.clone().to_string();
-    let username = config.core_rpc_user.clone();
-    let password = config.core_rpc_pass.clone();
+    let url = jds_config.core_rpc_url.clone() + ":" + &jds_config.core_rpc_port.clone().to_string();
+    let username = jds_config.core_rpc_user.clone();
+    let password = jds_config.core_rpc_pass.clone();
     // TODO should we manage what to do when the limit is reaced?
     let (new_block_sender, new_block_receiver): (Sender<String>, Receiver<String>) = bounded(10);
     let mempool = Arc::new(Mutex::new(mempool::JDsMempool::new(
@@ -113,7 +33,7 @@ async fn main() {
         password,
         new_block_receiver,
     )));
-    let mempool_update_interval = config.mempool_update_interval;
+    let mempool_update_interval = jds_config.mempool_update_interval;
     let mempool_cloned_ = mempool.clone();
     let (status_tx, status_rx) = unbounded();
     let sender = status::Sender::Downstream(status_tx.clone());
@@ -183,9 +103,9 @@ async fn main() {
         });
     };
 
-    info!("Jds INITIALIZING with config: {:?}", &args.config_path);
+    info!("Jds INITIALIZING");
 
-    let cloned = config.clone();
+    let cloned = jds_config.clone();
     let mempool_cloned = mempool.clone();
     let (sender_add_txs_to_mempool, receiver_add_txs_to_mempool) = unbounded();
     task::spawn(async move {
diff --git a/roles/mining-proxy/Cargo.toml b/roles/mining-proxy/Cargo.toml
index 951645fde3..c966b89180 100644
--- a/roles/mining-proxy/Cargo.toml
+++ b/roles/mining-proxy/Cargo.toml
@@ -25,8 +25,9 @@ once_cell = "1.12.0"
 roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" }
 serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false }
 tokio = { version = "1", features = ["full"] }
-toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" }
 tracing = {version = "0.1"}
 tracing-subscriber = {version = "0.3"}
 nohash-hasher = "0.2.0"
 key-utils = { version = "^1.0.0", path = "../../utils/key-utils" }
+clap = { version = "^4.5.4", features = ["derive"] }
+config = { version = "0.14.0", features = ["toml"] }
\ No newline at end of file
diff --git a/roles/mining-proxy/src/args.rs b/roles/mining-proxy/src/args.rs
new file mode 100644
index 0000000000..96208ee431
--- /dev/null
+++ b/roles/mining-proxy/src/args.rs
@@ -0,0 +1,28 @@
+use crate::lib::{error::ProxyResult, proxy_config::ProxyConfig};
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+struct Args {
+    #[arg(short, long, help = "Path to TOML configuration file")]
+    config_path: String,
+}
+
+#[allow(clippy::result_large_err)]
+pub fn process_cli_args() -> ProxyResult<ProxyConfig> {
+    let args = Args::parse();
+    let config = match config::Config::builder()
+        .add_source(config::File::with_name(&args.config_path))
+        .build()
+    {
+        Ok(cfg) => cfg,
+        Err(e) => {
+            tracing::error!("{:?}", e);
+            std::process::exit(1)
+        }
+    };
+
+    let proxy_config: ProxyConfig = config.try_deserialize()?;
+
+    Ok(proxy_config)
+}
diff --git a/roles/mining-proxy/src/lib/error.rs b/roles/mining-proxy/src/lib/error.rs
index b5c900bfd9..8df5a6b7b8 100644
--- a/roles/mining-proxy/src/lib/error.rs
+++ b/roles/mining-proxy/src/lib/error.rs
@@ -6,17 +6,33 @@ use std::net::SocketAddr;
 pub type Message = PoolMessages<'static>;
 pub type EitherFrame = StandardEitherFrame<Message>;
 
+pub type ProxyResult<T> = core::result::Result<T, ProxyError>;
+
 #[derive(Debug)]
 #[allow(clippy::large_enum_variant)]
 #[allow(clippy::enum_variant_names)]
-pub enum Error {
+pub enum ProxyError {
+    ConfigError(config::ConfigError),
+    Io(std::io::Error),
     SendError(SendError<EitherFrame>),
     UpstreamNotAvailabe(SocketAddr),
     SetupConnectionError(String),
 }
 
-impl From<SendError<EitherFrame>> for Error {
+impl From<config::ConfigError> for ProxyError {
+    fn from(e: config::ConfigError) -> ProxyError {
+        ProxyError::ConfigError(e)
+    }
+}
+
+impl From<std::io::Error> for ProxyError {
+    fn from(e: std::io::Error) -> ProxyError {
+        ProxyError::Io(e)
+    }
+}
+
+impl From<SendError<EitherFrame>> for ProxyError {
     fn from(error: SendError<EitherFrame>) -> Self {
-        Error::SendError(error)
+        ProxyError::SendError(error)
     }
 }
diff --git a/roles/mining-proxy/src/lib/mod.rs b/roles/mining-proxy/src/lib/mod.rs
index b9a9fd2f8d..227244a62b 100644
--- a/roles/mining-proxy/src/lib/mod.rs
+++ b/roles/mining-proxy/src/lib/mod.rs
@@ -1,5 +1,6 @@
 pub mod downstream_mining;
 pub mod error;
+pub mod proxy_config;
 pub mod upstream_mining;
 
 use once_cell::sync::OnceCell;
@@ -96,21 +97,10 @@ pub enum ChannelKind {
     Extended,
 }
 
-#[derive(Debug, Deserialize, Clone)]
-pub struct Config {
-    pub upstreams: Vec<UpstreamMiningValues>,
-    pub listen_address: String,
-    pub listen_mining_port: u16,
-    pub max_supported_version: u16,
-    pub min_supported_version: u16,
-    downstream_share_per_minute: f32,
-    expected_total_downstream_hr: f32,
-    reconnect: bool,
-}
 pub async fn initialize_r_logic(
     upstreams: &[UpstreamMiningValues],
     group_id: Arc<Mutex<GroupId>>,
-    config: Config,
+    config: proxy_config::ProxyConfig,
 ) -> RLogic {
     let channel_ids = Arc::new(Mutex::new(Id::new()));
     let mut upstream_mining_nodes = Vec::with_capacity(upstreams.len());
diff --git a/roles/mining-proxy/src/lib/proxy_config.rs b/roles/mining-proxy/src/lib/proxy_config.rs
new file mode 100644
index 0000000000..db063a3e25
--- /dev/null
+++ b/roles/mining-proxy/src/lib/proxy_config.rs
@@ -0,0 +1,14 @@
+use super::UpstreamMiningValues;
+use serde::Deserialize;
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct ProxyConfig {
+    pub upstreams: Vec<UpstreamMiningValues>,
+    pub listen_address: String,
+    pub listen_mining_port: u16,
+    pub max_supported_version: u16,
+    pub min_supported_version: u16,
+    pub downstream_share_per_minute: f32,
+    pub expected_total_downstream_hr: f32,
+    pub reconnect: bool,
+}
diff --git a/roles/mining-proxy/src/lib/upstream_mining.rs b/roles/mining-proxy/src/lib/upstream_mining.rs
index 61a5d0f31a..48aec9285b 100644
--- a/roles/mining-proxy/src/lib/upstream_mining.rs
+++ b/roles/mining-proxy/src/lib/upstream_mining.rs
@@ -274,7 +274,7 @@ impl UpstreamMiningNode {
     pub async fn send(
         self_mutex: Arc<Mutex<Self>>,
         sv2_frame: StdFrame,
-    ) -> Result<(), super::error::Error> {
+    ) -> Result<(), super::error::ProxyError> {
         let (has_sv2_connection, mut connection, address) = self_mutex
             .safe_lock(|self_| {
                 (
@@ -333,7 +333,7 @@ impl UpstreamMiningNode {
         }
     }
 
-    async fn receive(self_mutex: Arc<Mutex<Self>>) -> Result<StdFrame, super::error::Error> {
+    async fn receive(self_mutex: Arc<Mutex<Self>>) -> Result<StdFrame, super::error::ProxyError> {
         let mut connection = self_mutex
             .safe_lock(|self_| self_.connection.clone())
             .unwrap();
@@ -343,7 +343,7 @@ impl UpstreamMiningNode {
                 Err(_) => {
                     let address = self_mutex.safe_lock(|s| s.address).unwrap();
                     error!("Upstream node {} is not available", address);
-                    Err(super::error::Error::UpstreamNotAvailabe(address))
+                    Err(super::error::ProxyError::UpstreamNotAvailabe(address))
                 }
             },
             None => {
@@ -353,7 +353,7 @@ impl UpstreamMiningNode {
         }
     }
 
-    async fn connect(self_mutex: Arc<Mutex<Self>>) -> Result<(), super::error::Error> {
+    async fn connect(self_mutex: Arc<Mutex<Self>>) -> Result<(), super::error::ProxyError> {
         let has_connection = self_mutex
             .safe_lock(|self_| self_.connection.is_some())
             .unwrap();
@@ -365,7 +365,7 @@ impl UpstreamMiningNode {
                     .unwrap();
                 let socket = TcpStream::connect(address).await.map_err(|_| {
                     error!("Upstream node {} is not available", address);
-                    super::error::Error::UpstreamNotAvailabe(address)
+                    super::error::ProxyError::UpstreamNotAvailabe(address)
                 })?;
                 info!(
                     "Connected to upstream node {}: now handling noise handshake",
@@ -597,7 +597,7 @@ impl UpstreamMiningNode {
         flags: Option<u32>,
         min_version: u16,
         max_version: u16,
-    ) -> Result<(), super::error::Error> {
+    ) -> Result<(), super::error::ProxyError> {
         let flags = flags.unwrap_or(0b0000_0000_0000_0000_0000_0000_0000_0110);
         let (frame, downstream_hr) = self_mutex
             .safe_lock(|self_| {
@@ -650,7 +650,9 @@ impl UpstreamMiningNode {
                     let error_message = std::str::from_utf8(m.error_code.inner_as_ref())
                         .unwrap()
                         .to_string();
-                    Err(super::error::Error::SetupConnectionError(error_message))
+                    Err(super::error::ProxyError::SetupConnectionError(
+                        error_message,
+                    ))
                 }
             }
             Ok(_) => todo!(),
diff --git a/roles/mining-proxy/src/main.rs b/roles/mining-proxy/src/main.rs
index 0725c189b1..778a288d0d 100644
--- a/roles/mining-proxy/src/main.rs
+++ b/roles/mining-proxy/src/main.rs
@@ -18,75 +18,12 @@
 //! A Downstream that signal the incapacity to handle group channels can open only one channel.
 //!
 #![allow(special_module_name)]
+mod args;
 mod lib;
 
-use lib::Config;
 use roles_logic_sv2::utils::{GroupId, Mutex};
 use std::{net::SocketAddr, sync::Arc};
-use tracing::{error, info};
-
-mod args {
-    use std::path::PathBuf;
-
-    #[derive(Debug)]
-    pub struct Args {
-        pub config_path: PathBuf,
-    }
-
-    enum ArgsState {
-        Next,
-        ExpectPath,
-        Done,
-    }
-
-    enum ArgsResult {
-        Config(PathBuf),
-        None,
-        Help(String),
-    }
-
-    impl Args {
-        const DEFAULT_CONFIG_PATH: &'static str = "proxy-config.toml";
-        const HELP_MSG: &'static str =
-            "Usage: -h/--help, -c/--config <path|default proxy-config.toml>";
-
-        pub fn from_args() -> Result<Self, String> {
-            let cli_args = std::env::args();
-
-            if cli_args.len() == 1 {
-                println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH);
-                println!("{}\n", Self::HELP_MSG);
-            }
-
-            let config_path = cli_args
-                .scan(ArgsState::Next, |state, item| {
-                    match std::mem::replace(state, ArgsState::Done) {
-                        ArgsState::Next => match item.as_str() {
-                            "-c" | "--config" => {
-                                *state = ArgsState::ExpectPath;
-                                Some(ArgsResult::None)
-                            }
-                            "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())),
-                            _ => {
-                                *state = ArgsState::Next;
-
-                                Some(ArgsResult::None)
-                            }
-                        },
-                        ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))),
-                        ArgsState::Done => None,
-                    }
-                })
-                .last();
-            let config_path = match config_path {
-                Some(ArgsResult::Config(p)) => p,
-                Some(ArgsResult::Help(h)) => return Err(h),
-                _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH),
-            };
-            Ok(Self { config_path })
-        }
-    }
-}
+use tracing::info;
 
 /// 1. the proxy scan all the upstreams and map them
 /// 2. donwstream open a connetcion with proxy
@@ -101,39 +38,29 @@ mod args {
 #[tokio::main]
 async fn main() {
     tracing_subscriber::fmt::init();
-    let args = match args::Args::from_args() {
-        Ok(cfg) => cfg,
-        Err(help) => {
-            error!("{}", help);
-            return;
-        }
-    };
-
-    // Scan all the upstreams and map them
-    let config_file = std::fs::read_to_string(args.config_path.clone())
-        .unwrap_or_else(|_| panic!("Can not open {:?}", args.config_path));
-    let config = match toml::from_str::<Config>(&config_file) {
-        Ok(cfg) => cfg,
-        Err(e) => {
-            error!("Failed to parse config file: {}", e);
-            return;
-        }
+    let proxy_config = match args::process_cli_args() {
+        Ok(p) => p,
+        Err(_) => return,
     };
 
     let group_id = Arc::new(Mutex::new(GroupId::new()));
     lib::ROUTING_LOGIC
         .set(Mutex::new(
-            lib::initialize_r_logic(&config.upstreams, group_id, config.clone()).await,
+            lib::initialize_r_logic(&proxy_config.upstreams, group_id, proxy_config.clone()).await,
         ))
         .expect("BUG: Failed to set ROUTING_LOGIC");
     info!("PROXY INITIALIZING");
-    lib::initialize_upstreams(config.min_supported_version, config.max_supported_version).await;
+    lib::initialize_upstreams(
+        proxy_config.min_supported_version,
+        proxy_config.max_supported_version,
+    )
+    .await;
     info!("PROXY INITIALIZED");
 
     // Wait for downstream connection
     let socket = SocketAddr::new(
-        config.listen_address.parse().unwrap(),
-        config.listen_mining_port,
+        proxy_config.listen_address.parse().unwrap(),
+        proxy_config.listen_mining_port,
     );
 
     info!("PROXY INITIALIZED");
diff --git a/roles/pool/Cargo.toml b/roles/pool/Cargo.toml
index 3b62c74e1e..6ebe5219db 100644
--- a/roles/pool/Cargo.toml
+++ b/roles/pool/Cargo.toml
@@ -23,13 +23,14 @@ rand = "0.8.4"
 roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" }
 serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false }
 tokio = { version = "1", features = ["full"] }
-toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" }
 tracing = { version = "0.1" }
 tracing-subscriber = "0.3"
 async-recursion = "1.0.0"
 error_handling = { version = "1.0.0", path = "../../utils/error-handling" }
 nohash-hasher = "0.2.0"
 key-utils = { version = "^1.0.0", path = "../../utils/key-utils" }
+clap = { version = "^4.5.4", features = ["derive"] }
+config = { version = "0.14.0", features = ["toml"] }
 
 [dev-dependencies]
 hex = "0.4.3"
diff --git a/roles/pool/src/args.rs b/roles/pool/src/args.rs
new file mode 100644
index 0000000000..1f69639662
--- /dev/null
+++ b/roles/pool/src/args.rs
@@ -0,0 +1,29 @@
+use crate::lib::{error::PoolResult, pool_config::PoolConfig};
+
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+struct Args {
+    #[arg(short, long, help = "Path to TOML configuration file")]
+    config_path: String,
+}
+
+#[allow(clippy::result_large_err)]
+pub fn process_cli_args() -> PoolResult<PoolConfig> {
+    let args = Args::parse();
+    let config = match config::Config::builder()
+        .add_source(config::File::with_name(&args.config_path))
+        .build()
+    {
+        Ok(cfg) => cfg,
+        Err(e) => {
+            tracing::error!("{:?}", e);
+            std::process::exit(1)
+        }
+    };
+
+    let pool_config: PoolConfig = config.try_deserialize()?;
+
+    Ok(pool_config)
+}
diff --git a/roles/pool/src/lib/error.rs b/roles/pool/src/lib/error.rs
index ead10b8fa5..a5624cdb02 100644
--- a/roles/pool/src/lib/error.rs
+++ b/roles/pool/src/lib/error.rs
@@ -8,6 +8,7 @@ use roles_logic_sv2::parsers::Mining;
 
 #[derive(std::fmt::Debug)]
 pub enum PoolError {
+    ConfigError(config::ConfigError),
     Io(std::io::Error),
     ChannelSend(Box<dyn std::marker::Send + Debug>),
     ChannelRecv(async_channel::RecvError),
@@ -22,10 +23,17 @@ pub enum PoolError {
     Sv2ProtocolError((u32, Mining<'static>)),
 }
 
+impl From<config::ConfigError> for PoolError {
+    fn from(e: config::ConfigError) -> PoolError {
+        PoolError::ConfigError(e)
+    }
+}
+
 impl std::fmt::Display for PoolError {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         use PoolError::*;
         match self {
+            ConfigError(e) => write!(f, "Config error: {:?}", e),
             Io(ref e) => write!(f, "I/O error: `{:?}", e),
             ChannelSend(ref e) => write!(f, "Channel send failed: `{:?}`", e),
             ChannelRecv(ref e) => write!(f, "Channel recv failed: `{:?}`", e),
diff --git a/roles/pool/src/lib/mining_pool/mod.rs b/roles/pool/src/lib/mining_pool/mod.rs
index e189c5406a..414618452f 100644
--- a/roles/pool/src/lib/mining_pool/mod.rs
+++ b/roles/pool/src/lib/mining_pool/mod.rs
@@ -1,5 +1,6 @@
 use super::{
     error::{PoolError, PoolResult},
+    pool_config::PoolConfig,
     status,
 };
 use async_channel::{Receiver, Sender};
@@ -28,10 +29,7 @@ use std::{
     net::SocketAddr,
     sync::Arc,
 };
-use stratum_common::{
-    bitcoin::{Script, TxOut},
-    secp256k1,
-};
+use stratum_common::secp256k1;
 use tokio::{net::TcpListener, task};
 use tracing::{debug, error, info, warn};
 
@@ -43,23 +41,6 @@ pub mod message_handler;
 pub type Message = PoolMessages<'static>;
 pub type StdFrame = StandardSv2Frame<Message>;
 pub type EitherFrame = StandardEitherFrame<Message>;
-
-pub fn get_coinbase_output(config: &Configuration) -> Result<Vec<TxOut>, Error> {
-    let mut result = Vec::new();
-    for coinbase_output_pool in &config.coinbase_outputs {
-        let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?;
-        let output_script: Script = coinbase_output.try_into()?;
-        result.push(TxOut {
-            value: 0,
-            script_pubkey: output_script,
-        });
-    }
-    match result.is_empty() {
-        true => Err(Error::EmptyCoinbaseOutputs),
-        _ => Ok(result),
-    }
-}
-
 #[derive(Debug, Deserialize, Clone)]
 pub struct CoinbaseOutput {
     output_script_type: String,
@@ -338,7 +319,7 @@ impl Pool {
 
     async fn accept_incoming_connection(
         self_: Arc<Mutex<Pool>>,
-        config: Configuration,
+        config: PoolConfig,
     ) -> PoolResult<()> {
         let status_tx = self_.safe_lock(|s| s.status_tx.clone())?;
         let listener = TcpListener::bind(&config.listen_address).await?;
@@ -514,7 +495,7 @@ impl Pool {
     }
 
     pub fn start(
-        config: Configuration,
+        config: PoolConfig,
         new_template_rx: Receiver<NewTemplate<'static>>,
         new_prev_hash_rx: Receiver<SetNewPrevHash<'static>>,
         solution_sender: Sender<SubmitSolution<'static>>,
@@ -529,7 +510,7 @@ impl Pool {
             end: extranonce_len,
         };
         let ids = Arc::new(Mutex::new(roles_logic_sv2::utils::GroupId::new()));
-        let pool_coinbase_outputs = get_coinbase_output(&config);
+        let pool_coinbase_outputs = super::pool_config::get_coinbase_output(&config);
         info!("PUB KEY: {:?}", pool_coinbase_outputs);
         let extranonces = ExtendedExtranonce::new(range_0, range_1, range_2);
         let creator = JobsCreators::new(extranonce_len as u8);
@@ -664,16 +645,27 @@ mod test {
         bitcoin::{util::psbt::serialize::Serialize, Transaction, Witness},
     };
 
+    use super::super::pool_config::PoolConfig;
+
     // this test is used to verify the `coinbase_tx_prefix` and `coinbase_tx_suffix` values tested against in
     // message generator `stratum/test/message-generator/test/pool-sri-test-extended.json`
     #[test]
     fn test_coinbase_outputs_from_config() {
         // Load config
-        let config: super::Configuration = toml::from_str(
-            &std::fs::read_to_string("./config-examples/pool-config-local-tp-example.toml")
-                .unwrap(),
-        )
-        .unwrap();
+        let config = match config::Config::builder()
+            .add_source(config::File::with_name(
+                "./config-examples/pool-config-local-tp-example.toml",
+            ))
+            .build()
+        {
+            Ok(cfg) => cfg,
+            Err(e) => {
+                tracing::error!("{:?}", e);
+                std::process::exit(1)
+            }
+        };
+
+        let pool_config: PoolConfig = config.try_deserialize().unwrap();
         // template from message generator test (mock TP template)
         let _extranonce_len = 3;
         let coinbase_prefix = vec![3, 76, 163, 38, 0];
@@ -683,15 +675,16 @@ mod test {
         let _coinbase_tx_value_remaining: u64 = 625000000;
         let _coinbase_tx_outputs_count = 0;
         let coinbase_tx_locktime = 0;
-        let coinbase_tx_outputs: Vec<bitcoin::TxOut> = super::get_coinbase_output(&config).unwrap();
+        let coinbase_tx_outputs: Vec<bitcoin::TxOut> =
+            super::super::pool_config::get_coinbase_output(&pool_config).unwrap();
         // extranonce len set to max_extranonce_size in `ChannelFactory::new_extended_channel()`
         let extranonce_len = 32;
 
         // build coinbase TX from 'job_creator::coinbase()'
 
         let mut bip34_bytes = get_bip_34_bytes(coinbase_prefix.try_into().unwrap());
-        let script_prefix_length = bip34_bytes.len() + config.pool_signature.as_bytes().len();
-        bip34_bytes.extend_from_slice(config.pool_signature.as_bytes());
+        let script_prefix_length = bip34_bytes.len() + pool_config.pool_signature.as_bytes().len();
+        bip34_bytes.extend_from_slice(pool_config.pool_signature.as_bytes());
         bip34_bytes.extend_from_slice(&vec![0; extranonce_len as usize]);
         let witness = match bip34_bytes.len() {
             0 => Witness::from_vec(vec![]),
@@ -776,13 +769,13 @@ mod test {
             _ => 2,
         };
         let r = encoded[4    // tx version
-        + segwit_bytes
-        + 1  // number of inputs TODO can be also 3
-        + 32 // prev OutPoint
-        + 4  // index
-        + 1  // bytes in script TODO can be also 3
-        + script_prefix_len  // bip34_bytes
-        + (extranonce_len as usize)..]
+            + segwit_bytes
+            + 1  // number of inputs TODO can be also 3
+            + 32 // prev OutPoint
+            + 4  // index
+            + 1  // bytes in script TODO can be also 3
+            + script_prefix_len  // bip34_bytes
+            + (extranonce_len as usize)..]
             .to_vec();
         r.try_into().unwrap()
     }
diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs
index 2d8417842d..b12ca52e5b 100644
--- a/roles/pool/src/lib/mod.rs
+++ b/roles/pool/src/lib/mod.rs
@@ -1,4 +1,5 @@
 pub mod error;
 pub mod mining_pool;
+pub mod pool_config;
 pub mod status;
 pub mod template_receiver;
diff --git a/roles/pool/src/lib/pool_config.rs b/roles/pool/src/lib/pool_config.rs
new file mode 100644
index 0000000000..f76444f257
--- /dev/null
+++ b/roles/pool/src/lib/pool_config.rs
@@ -0,0 +1,57 @@
+use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey};
+use roles_logic_sv2::{errors::Error, utils::CoinbaseOutput as CoinbaseOutput_};
+use serde::Deserialize;
+use std::convert::{TryFrom, TryInto};
+use stratum_common::bitcoin::{Script, TxOut};
+
+pub fn get_coinbase_output(config: &PoolConfig) -> Result<Vec<TxOut>, Error> {
+    let mut result = Vec::new();
+    for coinbase_output_pool in &config.coinbase_outputs {
+        let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?;
+        let output_script: Script = coinbase_output.try_into()?;
+        result.push(TxOut {
+            value: 0,
+            script_pubkey: output_script,
+        });
+    }
+    match result.is_empty() {
+        true => Err(Error::EmptyCoinbaseOutputs),
+        _ => Ok(result),
+    }
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct CoinbaseOutput {
+    output_script_type: String,
+    output_script_value: String,
+}
+
+impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ {
+    type Error = Error;
+
+    fn try_from(pool_output: &CoinbaseOutput) -> Result<Self, Self::Error> {
+        match pool_output.output_script_type.as_str() {
+            "TEST" | "P2PK" | "P2PKH" | "P2WPKH" | "P2SH" | "P2WSH" | "P2TR" => {
+                Ok(CoinbaseOutput_ {
+                    output_script_type: pool_output.clone().output_script_type,
+                    output_script_value: pool_output.clone().output_script_value,
+                })
+            }
+            _ => Err(Error::UnknownOutputScriptType),
+        }
+    }
+}
+
+#[derive(Debug, Deserialize, Clone)]
+pub struct PoolConfig {
+    pub listen_address: String,
+    pub tp_address: String,
+    pub tp_authority_public_key: Option<Secp256k1PublicKey>,
+    pub authority_public_key: Secp256k1PublicKey,
+    pub authority_secret_key: Secp256k1SecretKey,
+    pub cert_validity_sec: u64,
+    pub coinbase_outputs: Vec<CoinbaseOutput>,
+    pub pool_signature: String,
+    #[cfg(feature = "test_only_allow_unencrypted")]
+    pub test_only_listen_adress_plain: String,
+}
diff --git a/roles/pool/src/lib/status.rs b/roles/pool/src/lib/status.rs
index f9bd7a4bc3..43179c7e77 100644
--- a/roles/pool/src/lib/status.rs
+++ b/roles/pool/src/lib/status.rs
@@ -114,6 +114,9 @@ async fn send_status(
 pub async fn handle_error(sender: &Sender, e: PoolError) -> error_handling::ErrorBranch {
     tracing::debug!("Error: {:?}", &e);
     match e {
+        PoolError::ConfigError(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
         PoolError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         PoolError::ChannelSend(_) => {
             //This should be a continue because if we fail to send to 1 downstream we should continue
diff --git a/roles/pool/src/main.rs b/roles/pool/src/main.rs
index 169243c235..aabfe1d6da 100644
--- a/roles/pool/src/main.rs
+++ b/roles/pool/src/main.rs
@@ -2,103 +2,21 @@
 use async_channel::{bounded, unbounded};
 
 use tracing::{error, info, warn};
+mod args;
 mod lib;
 use lib::{
-    mining_pool::{get_coinbase_output, Configuration, Pool},
-    status,
-    template_receiver::TemplateRx,
+    mining_pool::Pool, pool_config::get_coinbase_output, status, template_receiver::TemplateRx,
 };
 
 use tokio::select;
 
-mod args {
-    use std::path::PathBuf;
-
-    #[derive(Debug)]
-    pub struct Args {
-        pub config_path: PathBuf,
-    }
-
-    enum ArgsState {
-        Next,
-        ExpectPath,
-        Done,
-    }
-
-    enum ArgsResult {
-        Config(PathBuf),
-        None,
-        Help(String),
-    }
-
-    impl Args {
-        const DEFAULT_CONFIG_PATH: &'static str = "pool-config.toml";
-        const HELP_MSG: &'static str =
-            "Usage: -h/--help, -c/--config <path|default pool-config.toml>";
-
-        pub fn from_args() -> Result<Self, String> {
-            let cli_args = std::env::args();
-
-            if cli_args.len() == 1 {
-                println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH);
-                println!("{}\n", Self::HELP_MSG);
-            }
-
-            let config_path = cli_args
-                .scan(ArgsState::Next, |state, item| {
-                    match std::mem::replace(state, ArgsState::Done) {
-                        ArgsState::Next => match item.as_str() {
-                            "-c" | "--config" => {
-                                *state = ArgsState::ExpectPath;
-                                Some(ArgsResult::None)
-                            }
-                            "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())),
-                            _ => {
-                                *state = ArgsState::Next;
-
-                                Some(ArgsResult::None)
-                            }
-                        },
-                        ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))),
-                        ArgsState::Done => None,
-                    }
-                })
-                .last();
-            let config_path = match config_path {
-                Some(ArgsResult::Config(p)) => p,
-                Some(ArgsResult::Help(h)) => return Err(h),
-                _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH),
-            };
-            Ok(Self { config_path })
-        }
-    }
-}
-
 #[tokio::main]
 async fn main() {
     tracing_subscriber::fmt::init();
 
-    let args = match args::Args::from_args() {
-        Ok(cfg) => cfg,
-        Err(help) => {
-            error!("{}", help);
-            return;
-        }
-    };
-
-    // Load config
-    let config: Configuration = match std::fs::read_to_string(&args.config_path) {
-        Ok(c) => match toml::from_str(&c) {
-            Ok(c) => c,
-            Err(e) => {
-                error!("Failed to parse config: {}", e);
-                return;
-            }
-        },
-        Err(e) => {
-            error!("Failed to read config: {}", e);
-            return;
-        }
+    let pool_config = match args::process_cli_args() {
+        Ok(p) => p,
+        Err(_) => return,
     };
 
     let (status_tx, status_rx) = unbounded();
@@ -106,8 +24,8 @@ async fn main() {
     let (s_prev_hash, r_prev_hash) = bounded(10);
     let (s_solution, r_solution) = bounded(10);
     let (s_message_recv_signal, r_message_recv_signal) = bounded(10);
-    info!("Pool INITIALIZING with config: {:?}", &args.config_path);
-    let coinbase_output_result = get_coinbase_output(&config);
+    info!("Pool INITIALIZING");
+    let coinbase_output_result = get_coinbase_output(&pool_config);
     let coinbase_output_len = match coinbase_output_result {
         Ok(coinbase_output) => coinbase_output.len() as u32,
         Err(err) => {
@@ -115,9 +33,9 @@ async fn main() {
             return;
         }
     };
-    let tp_authority_public_key = config.tp_authority_public_key;
+    let tp_authority_public_key = pool_config.tp_authority_public_key;
     let template_rx_res = TemplateRx::connect(
-        config.tp_address.parse().unwrap(),
+        pool_config.tp_address.parse().unwrap(),
         s_new_t,
         s_prev_hash,
         r_solution,
@@ -134,7 +52,7 @@ async fn main() {
     }
 
     let pool = Pool::start(
-        config.clone(),
+        pool_config.clone(),
         r_new_t,
         r_prev_hash,
         s_solution,
diff --git a/roles/translator/Cargo.toml b/roles/translator/Cargo.toml
index 182370cbd4..e6327050cb 100644
--- a/roles/translator/Cargo.toml
+++ b/roles/translator/Cargo.toml
@@ -26,7 +26,6 @@ serde = { version = "1.0.89", default-features = false, features = ["derive", "a
 serde_json = { version = "1.0.64", default-features = false, features = ["alloc"] }
 futures = "0.3.25"
 tokio = { version = "1", features = ["full"] }
-toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" }
 tracing = { version = "0.1" }
 tracing-subscriber = { version = "0.3" }
 v1 = { version = "^1.0.0", path = "../../protocols/v1", package="sv1_api" }
@@ -34,7 +33,8 @@ error_handling = { version = "1.0.0", path = "../../utils/error-handling" }
 key-utils = { version = "^1.0.0", path = "../../utils/key-utils" }
 tokio-util = { version = "0.7.10", features = ["codec"] }
 async-compat = "0.2.1"
-
+clap = { version = "^4.5.4", features = ["derive"] }
+config = { version = "0.14.0", features = ["toml"] }
 
 
 [dev-dependencies]
diff --git a/roles/translator/src/args.rs b/roles/translator/src/args.rs
index bf5e51c19d..2408a1d2cd 100644
--- a/roles/translator/src/args.rs
+++ b/roles/translator/src/args.rs
@@ -1,68 +1,29 @@
-use std::path::PathBuf;
+use crate::lib::{error::TProxyResult, tproxy_config::TProxyConfig};
 
-#[derive(Debug)]
-pub struct Args {
-    pub config_path: PathBuf,
-}
-
-enum ArgsState {
-    Next,
-    ExpectPath,
-    Done,
-}
+use clap::Parser;
 
-enum ArgsResult {
-    Config(PathBuf),
-    None,
-    Help(String),
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+struct Args {
+    #[arg(short, long, help = "Path to TOML configuration file")]
+    config_path: String,
 }
 
-impl Args {
-    const DEFAULT_CONFIG_PATH: &'static str = "proxy-config.toml";
-    const HELP_MSG: &'static str = "Usage: -h/--help, -c/--config <path|default proxy-config.toml>";
-
-    pub fn from_args() -> Result<Self, String> {
-        let cli_args = std::env::args();
-
-        if cli_args.len() == 1 {
-            println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH);
-            println!("{}\n", Self::HELP_MSG);
+#[allow(clippy::result_large_err)]
+pub fn process_cli_args<'a>() -> TProxyResult<'a, TProxyConfig> {
+    let args = Args::parse();
+    let config = match config::Config::builder()
+        .add_source(config::File::with_name(&args.config_path))
+        .build()
+    {
+        Ok(cfg) => cfg,
+        Err(e) => {
+            tracing::error!("{:?}", e);
+            std::process::exit(1)
         }
+    };
 
-        let config_path = cli_args
-            .scan(ArgsState::Next, |state, item| {
-                match std::mem::replace(state, ArgsState::Done) {
-                    ArgsState::Next => match item.as_str() {
-                        "-c" | "--config" => {
-                            *state = ArgsState::ExpectPath;
-                            Some(ArgsResult::None)
-                        }
-                        "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())),
-                        _ => {
-                            *state = ArgsState::Next;
+    let proxy_config: TProxyConfig = config.try_deserialize()?;
 
-                            Some(ArgsResult::None)
-                        }
-                    },
-                    ArgsState::ExpectPath => {
-                        let path = PathBuf::from(item.clone());
-                        if !path.exists() {
-                            return Some(ArgsResult::Help(format!(
-                                "Error: File '{}' does not exist!",
-                                path.display()
-                            )));
-                        }
-                        Some(ArgsResult::Config(path))
-                    }
-                    ArgsState::Done => None,
-                }
-            })
-            .last();
-        let config_path = match config_path {
-            Some(ArgsResult::Config(p)) => p,
-            Some(ArgsResult::Help(h)) => return Err(h),
-            _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH),
-        };
-        Ok(Self { config_path })
-    }
+    Ok(proxy_config)
 }
diff --git a/roles/translator/src/lib/downstream_sv1/diff_management.rs b/roles/translator/src/lib/downstream_sv1/diff_management.rs
index eb8f0af383..c170481db2 100644
--- a/roles/translator/src/lib/downstream_sv1/diff_management.rs
+++ b/roles/translator/src/lib/downstream_sv1/diff_management.rs
@@ -1,6 +1,6 @@
 use super::{Downstream, DownstreamMessages, SetDownstreamTarget};
 
-use super::super::error::{Error, ProxyResult};
+use super::super::error::{TProxyError, TProxyResult};
 use roles_logic_sv2::utils::Mutex;
 use std::{ops::Div, sync::Arc};
 use v1::json_rpc;
@@ -14,7 +14,7 @@ impl Downstream {
     pub async fn init_difficulty_management(
         self_: Arc<Mutex<Self>>,
         init_target: &[u8],
-    ) -> ProxyResult<'static, ()> {
+    ) -> TProxyResult<'static, ()> {
         let (connection_id, upstream_difficulty_config, miner_hashrate) = self_
             .safe_lock(|d| {
                 let timestamp_secs = std::time::SystemTime::now()
@@ -29,13 +29,13 @@ impl Downstream {
                     d.difficulty_mgmt.min_individual_miner_hashrate,
                 )
             })
-            .map_err(|_e| Error::PoisonLock)?;
+            .map_err(|_e| TProxyError::PoisonLock)?;
         // add new connection hashrate to channel hashrate
         upstream_difficulty_config
             .safe_lock(|u| {
                 u.channel_nominal_hashrate += miner_hashrate;
             })
-            .map_err(|_e| Error::PoisonLock)?;
+            .map_err(|_e| TProxyError::PoisonLock)?;
         // update downstream target with bridge
         let init_target = binary_sv2::U256::try_from(init_target.to_vec())?;
         Self::send_message_upstream(
@@ -52,7 +52,9 @@ impl Downstream {
 
     /// Called before a miner disconnects so we can remove the miner's hashrate from the aggregated channel hashrate
     #[allow(clippy::result_large_err)]
-    pub fn remove_miner_hashrate_from_channel(self_: Arc<Mutex<Self>>) -> ProxyResult<'static, ()> {
+    pub fn remove_miner_hashrate_from_channel(
+        self_: Arc<Mutex<Self>>,
+    ) -> TProxyResult<'static, ()> {
         self_
             .safe_lock(|d| {
                 d.upstream_difficulty_config
@@ -64,9 +66,9 @@ impl Downstream {
                             u.channel_nominal_hashrate = 0.0;
                         }
                     })
-                    .map_err(|_e| Error::PoisonLock)
+                    .map_err(|_e| TProxyError::PoisonLock)
             })
-            .map_err(|_e| Error::PoisonLock)??;
+            .map_err(|_e| TProxyError::PoisonLock)??;
         Ok(())
     }
 
@@ -74,11 +76,11 @@ impl Downstream {
     /// difficulty to the miner
     pub async fn try_update_difficulty_settings(
         self_: Arc<Mutex<Self>>,
-    ) -> ProxyResult<'static, ()> {
+    ) -> TProxyResult<'static, ()> {
         let (diff_mgmt, channel_id) = self_
             .clone()
             .safe_lock(|d| (d.difficulty_mgmt.clone(), d.connection_id))
-            .map_err(|_e| Error::PoisonLock)?;
+            .map_err(|_e| TProxyError::PoisonLock)?;
         tracing::debug!(
             "Time of last diff update: {:?}",
             diff_mgmt.timestamp_of_last_update
@@ -92,7 +94,7 @@ impl Downstream {
             diff_mgmt.shares_per_minute.into(),
         ) {
             Ok(target) => target.to_vec(),
-            Err(v) => return Err(Error::TargetError(v)),
+            Err(v) => return Err(TProxyError::TargetError(v)),
         };
         if let Some(new_hash_rate) =
             Self::update_miner_hashrate(self_.clone(), prev_target.clone())?
@@ -102,7 +104,7 @@ impl Downstream {
                 diff_mgmt.shares_per_minute.into(),
             ) {
                 Ok(target) => target,
-                Err(v) => return Err(Error::TargetError(v)),
+                Err(v) => return Err(TProxyError::TargetError(v)),
             };
             tracing::debug!("New target from hashrate: {:?}", new_target.inner_as_ref());
             let message = Self::get_set_difficulty(new_target.to_vec())?;
@@ -124,7 +126,7 @@ impl Downstream {
 
     /// calculates the target according to the current stored hashrate of the miner
     #[allow(clippy::result_large_err)]
-    pub fn hash_rate_to_target(self_: Arc<Mutex<Self>>) -> ProxyResult<'static, Vec<u8>> {
+    pub fn hash_rate_to_target(self_: Arc<Mutex<Self>>) -> TProxyResult<'static, Vec<u8>> {
         self_
             .safe_lock(|d| {
                 match roles_logic_sv2::utils::hash_rate_to_target(
@@ -132,20 +134,20 @@ impl Downstream {
                     d.difficulty_mgmt.shares_per_minute.into(),
                 ) {
                     Ok(target) => Ok(target.to_vec()),
-                    Err(e) => Err(Error::TargetError(e)),
+                    Err(e) => Err(TProxyError::TargetError(e)),
                 }
             })
-            .map_err(|_e| Error::PoisonLock)?
+            .map_err(|_e| TProxyError::PoisonLock)?
     }
 
     /// increments the number of shares since the last difficulty update
     #[allow(clippy::result_large_err)]
-    pub(super) fn save_share(self_: Arc<Mutex<Self>>) -> ProxyResult<'static, ()> {
+    pub(super) fn save_share(self_: Arc<Mutex<Self>>) -> TProxyResult<'static, ()> {
         self_
             .safe_lock(|d| {
                 d.difficulty_mgmt.submits_since_last_update += 1;
             })
-            .map_err(|_e| Error::PoisonLock)?;
+            .map_err(|_e| TProxyError::PoisonLock)?;
         Ok(())
     }
 
@@ -153,7 +155,7 @@ impl Downstream {
     /// difficulty for the Downstream role and creates the SV1 `mining.set_difficulty` message to
     /// be sent to the Downstream role.
     #[allow(clippy::result_large_err)]
-    pub(super) fn get_set_difficulty(target: Vec<u8>) -> ProxyResult<'static, json_rpc::Message> {
+    pub(super) fn get_set_difficulty(target: Vec<u8>) -> TProxyResult<'static, json_rpc::Message> {
         let value = Downstream::difficulty_from_target(target)?;
         tracing::debug!("Difficulty from target: {:?}", value);
         let set_target = v1::methods::server_to_client::SetDifficulty { value };
@@ -164,7 +166,7 @@ impl Downstream {
     /// Converts target received by the `SetTarget` SV2 message from the Upstream role into the
     /// difficulty for the Downstream role sent via the SV1 `mining.set_difficulty` message.
     #[allow(clippy::result_large_err)]
-    pub(super) fn difficulty_from_target(mut target: Vec<u8>) -> ProxyResult<'static, f64> {
+    pub(super) fn difficulty_from_target(mut target: Vec<u8>) -> TProxyResult<'static, f64> {
         // reverse because target is LE and this function relies on BE
         target.reverse();
         let target = target.as_slice();
@@ -199,7 +201,7 @@ impl Downstream {
     pub fn update_miner_hashrate(
         self_: Arc<Mutex<Self>>,
         miner_target: Vec<u8>,
-    ) -> ProxyResult<'static, Option<f32>> {
+    ) -> TProxyResult<'static, Option<f32>> {
         self_
             .safe_lock(|d| {
                 let timestamp_secs = std::time::SystemTime::now()
@@ -287,7 +289,7 @@ impl Downstream {
                     Ok(None)
                 }
             })
-            .map_err(|_e| Error::PoisonLock)?
+            .map_err(|_e| TProxyError::PoisonLock)?
     }
 
     /// Helper function to check if target is set to zero for some reason (typically happens when
@@ -304,7 +306,7 @@ impl Downstream {
 
 #[cfg(test)]
 mod test {
-    use crate::proxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig};
+    use crate::tproxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig};
     use async_channel::unbounded;
     use binary_sv2::U256;
     use rand::{thread_rng, Rng};
diff --git a/roles/translator/src/lib/downstream_sv1/downstream.rs b/roles/translator/src/lib/downstream_sv1/downstream.rs
index ddf74fe589..ba1c3a99cf 100644
--- a/roles/translator/src/lib/downstream_sv1/downstream.rs
+++ b/roles/translator/src/lib/downstream_sv1/downstream.rs
@@ -1,8 +1,8 @@
 use crate::{
     downstream_sv1,
-    error::ProxyResult,
-    proxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig},
+    error::TProxyResult,
     status,
+    tproxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig},
 };
 use async_channel::{bounded, Receiver, Sender};
 use async_std::{
@@ -22,7 +22,7 @@ use roles_logic_sv2::{
     utils::Mutex,
 };
 
-use crate::error::Error;
+use crate::error::TProxyError;
 use futures::select;
 use tokio_util::codec::{FramedRead, LinesCodec};
 
@@ -181,7 +181,7 @@ impl Downstream {
                                 handle_result!(tx_status_reader, res);
                             }
                             Some(Err(_)) => {
-                                handle_result!(tx_status_reader, Err(Error::Sv1MessageTooLong));
+                                handle_result!(tx_status_reader, Err(TProxyError::Sv1MessageTooLong));
                             }
                             None => {
                                 handle_result!(tx_status_reader, Err(
@@ -375,7 +375,7 @@ impl Downstream {
     async fn handle_incoming_sv1(
         self_: Arc<Mutex<Self>>,
         message_sv1: json_rpc::Message,
-    ) -> Result<(), super::super::error::Error<'static>> {
+    ) -> Result<(), super::super::error::TProxyError<'static>> {
         // `handle_message` in `IsServer` trait + calls `handle_request`
         // TODO: Map err from V1Error to Error::V1Error
         let response = self_.safe_lock(|s| s.handle_message(message_sv1)).unwrap();
@@ -417,7 +417,7 @@ impl Downstream {
     pub(super) async fn send_message_upstream(
         self_: Arc<Mutex<Self>>,
         msg: DownstreamMessages,
-    ) -> ProxyResult<'static, ()> {
+    ) -> TProxyResult<'static, ()> {
         let sender = self_.safe_lock(|s| s.tx_sv1_bridge.clone()).unwrap();
         debug!("To Bridge: {:?}", msg);
         let _ = sender.send(msg).await;
diff --git a/roles/translator/src/lib/error.rs b/roles/translator/src/lib/error.rs
index debad1819a..36f60b741f 100644
--- a/roles/translator/src/lib/error.rs
+++ b/roles/translator/src/lib/error.rs
@@ -7,7 +7,7 @@ use v1::server_to_client::{Notify, SetDifficulty};
 
 use stratum_common::bitcoin::util::uint::ParseLengthError;
 
-pub type ProxyResult<'a, T> = core::result::Result<T, Error<'a>>;
+pub type TProxyResult<'a, T> = core::result::Result<T, TProxyError<'a>>;
 
 #[derive(Debug)]
 pub enum ChannelSendError<'a> {
@@ -32,14 +32,14 @@ pub enum ChannelSendError<'a> {
 }
 
 #[derive(Debug)]
-pub enum Error<'a> {
+pub enum TProxyError<'a> {
     VecToSlice32(Vec<u8>),
+    ConfigError(config::ConfigError),
     /// Errors on bad CLI argument input.
+    #[allow(dead_code)]
     BadCliArgs,
     /// Errors on bad `serde_json` serialize/deserialize.
     BadSerdeJson(serde_json::Error),
-    /// Errors on bad `toml` deserialize.
-    BadTomlDeserialize(toml::de::Error),
     /// Errors from `binary_sv2` crate.
     BinarySv2(binary_sv2::Error),
     /// Errors on bad noise handshake.
@@ -77,13 +77,13 @@ pub enum Error<'a> {
     Sv1MessageTooLong,
 }
 
-impl<'a> fmt::Display for Error<'a> {
+impl<'a> fmt::Display for TProxyError<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        use Error::*;
+        use TProxyError::*;
         match self {
+            ConfigError(e) => write!(f, "Config error: {:?}", e),
             BadCliArgs => write!(f, "Bad CLI arg input"),
             BadSerdeJson(ref e) => write!(f, "Bad serde json: `{:?}`", e),
-            BadTomlDeserialize(ref e) => write!(f, "Bad `toml` deserialize: `{:?}`", e),
             BinarySv2(ref e) => write!(f, "Binary SV2 error: `{:?}`", e),
             CodecNoise(ref e) => write!(f, "Noise error: `{:?}", e),
             FramingSv2(ref e) => write!(f, "Framing SV2 error: `{:?}`", e),
@@ -117,125 +117,125 @@ impl<'a> fmt::Display for Error<'a> {
     }
 }
 
-impl<'a> From<binary_sv2::Error> for Error<'a> {
+impl<'a> From<config::ConfigError> for TProxyError<'a> {
+    fn from(e: config::ConfigError) -> TProxyError<'a> {
+        TProxyError::ConfigError(e)
+    }
+}
+
+impl<'a> From<binary_sv2::Error> for TProxyError<'a> {
     fn from(e: binary_sv2::Error) -> Self {
-        Error::BinarySv2(e)
+        TProxyError::BinarySv2(e)
     }
 }
 
-impl<'a> From<codec_sv2::noise_sv2::Error> for Error<'a> {
+impl<'a> From<codec_sv2::noise_sv2::Error> for TProxyError<'a> {
     fn from(e: codec_sv2::noise_sv2::Error) -> Self {
-        Error::CodecNoise(e)
+        TProxyError::CodecNoise(e)
     }
 }
 
-impl<'a> From<framing_sv2::Error> for Error<'a> {
+impl<'a> From<framing_sv2::Error> for TProxyError<'a> {
     fn from(e: framing_sv2::Error) -> Self {
-        Error::FramingSv2(e)
+        TProxyError::FramingSv2(e)
     }
 }
 
-impl<'a> From<std::io::Error> for Error<'a> {
+impl<'a> From<std::io::Error> for TProxyError<'a> {
     fn from(e: std::io::Error) -> Self {
-        Error::Io(e)
+        TProxyError::Io(e)
     }
 }
 
-impl<'a> From<std::num::ParseIntError> for Error<'a> {
+impl<'a> From<std::num::ParseIntError> for TProxyError<'a> {
     fn from(e: std::num::ParseIntError) -> Self {
-        Error::ParseInt(e)
+        TProxyError::ParseInt(e)
     }
 }
 
-impl<'a> From<roles_logic_sv2::errors::Error> for Error<'a> {
+impl<'a> From<roles_logic_sv2::errors::Error> for TProxyError<'a> {
     fn from(e: roles_logic_sv2::errors::Error) -> Self {
-        Error::RolesSv2Logic(e)
+        TProxyError::RolesSv2Logic(e)
     }
 }
 
-impl<'a> From<serde_json::Error> for Error<'a> {
+impl<'a> From<serde_json::Error> for TProxyError<'a> {
     fn from(e: serde_json::Error) -> Self {
-        Error::BadSerdeJson(e)
-    }
-}
-
-impl<'a> From<toml::de::Error> for Error<'a> {
-    fn from(e: toml::de::Error) -> Self {
-        Error::BadTomlDeserialize(e)
+        TProxyError::BadSerdeJson(e)
     }
 }
 
-impl<'a> From<v1::error::Error<'a>> for Error<'a> {
+impl<'a> From<v1::error::Error<'a>> for TProxyError<'a> {
     fn from(e: v1::error::Error<'a>) -> Self {
-        Error::V1Protocol(e)
+        TProxyError::V1Protocol(e)
     }
 }
 
-impl<'a> From<async_channel::RecvError> for Error<'a> {
+impl<'a> From<async_channel::RecvError> for TProxyError<'a> {
     fn from(e: async_channel::RecvError) -> Self {
-        Error::ChannelErrorReceiver(e)
+        TProxyError::ChannelErrorReceiver(e)
     }
 }
 
-impl<'a> From<tokio::sync::broadcast::error::RecvError> for Error<'a> {
+impl<'a> From<tokio::sync::broadcast::error::RecvError> for TProxyError<'a> {
     fn from(e: tokio::sync::broadcast::error::RecvError) -> Self {
-        Error::TokioChannelErrorRecv(e)
+        TProxyError::TokioChannelErrorRecv(e)
     }
 }
 
 //*** LOCK ERRORS ***
-impl<'a, T> From<PoisonError<T>> for Error<'a> {
+impl<'a, T> From<PoisonError<T>> for TProxyError<'a> {
     fn from(_e: PoisonError<T>) -> Self {
-        Error::PoisonLock
+        TProxyError::PoisonLock
     }
 }
 
 // *** CHANNEL SENDER ERRORS ***
 impl<'a> From<async_channel::SendError<roles_logic_sv2::mining_sv2::SubmitSharesExtended<'a>>>
-    for Error<'a>
+    for TProxyError<'a>
 {
     fn from(
         e: async_channel::SendError<roles_logic_sv2::mining_sv2::SubmitSharesExtended<'a>>,
     ) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e))
     }
 }
 
 impl<'a> From<async_channel::SendError<roles_logic_sv2::mining_sv2::SetNewPrevHash<'a>>>
-    for Error<'a>
+    for TProxyError<'a>
 {
     fn from(e: async_channel::SendError<roles_logic_sv2::mining_sv2::SetNewPrevHash<'a>>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e))
     }
 }
 
-impl<'a> From<tokio::sync::broadcast::error::SendError<Notify<'a>>> for Error<'a> {
+impl<'a> From<tokio::sync::broadcast::error::SendError<Notify<'a>>> for TProxyError<'a> {
     fn from(e: tokio::sync::broadcast::error::SendError<Notify<'a>>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::Notify(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::Notify(e))
     }
 }
 
-impl<'a> From<async_channel::SendError<v1::Message>> for Error<'a> {
+impl<'a> From<async_channel::SendError<v1::Message>> for TProxyError<'a> {
     fn from(e: async_channel::SendError<v1::Message>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::V1Message(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::V1Message(e))
     }
 }
 
-impl<'a> From<async_channel::SendError<(ExtendedExtranonce, u32)>> for Error<'a> {
+impl<'a> From<async_channel::SendError<(ExtendedExtranonce, u32)>> for TProxyError<'a> {
     fn from(e: async_channel::SendError<(ExtendedExtranonce, u32)>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::Extranonce(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::Extranonce(e))
     }
 }
 
-impl<'a> From<async_channel::SendError<NewExtendedMiningJob<'a>>> for Error<'a> {
+impl<'a> From<async_channel::SendError<NewExtendedMiningJob<'a>>> for TProxyError<'a> {
     fn from(e: async_channel::SendError<NewExtendedMiningJob<'a>>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e))
     }
 }
 
-impl<'a> From<async_channel::SendError<SetCustomMiningJob<'a>>> for Error<'a> {
+impl<'a> From<async_channel::SendError<SetCustomMiningJob<'a>>> for TProxyError<'a> {
     fn from(e: async_channel::SendError<SetCustomMiningJob<'a>>) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e))
     }
 }
 
@@ -245,7 +245,7 @@ impl<'a>
             roles_logic_sv2::template_distribution_sv2::SetNewPrevHash<'a>,
             Vec<u8>,
         )>,
-    > for Error<'a>
+    > for TProxyError<'a>
 {
     fn from(
         e: async_channel::SendError<(
@@ -253,36 +253,36 @@ impl<'a>
             Vec<u8>,
         )>,
     ) -> Self {
-        Error::ChannelErrorSender(ChannelSendError::NewTemplate(e))
+        TProxyError::ChannelErrorSender(ChannelSendError::NewTemplate(e))
     }
 }
 
-impl<'a> From<Vec<u8>> for Error<'a> {
+impl<'a> From<Vec<u8>> for TProxyError<'a> {
     fn from(e: Vec<u8>) -> Self {
-        Error::VecToSlice32(e)
+        TProxyError::VecToSlice32(e)
     }
 }
 
-impl<'a> From<ParseLengthError> for Error<'a> {
+impl<'a> From<ParseLengthError> for TProxyError<'a> {
     fn from(e: ParseLengthError) -> Self {
-        Error::Uint256Conversion(e)
+        TProxyError::Uint256Conversion(e)
     }
 }
 
-impl<'a> From<SetDifficulty> for Error<'a> {
+impl<'a> From<SetDifficulty> for TProxyError<'a> {
     fn from(e: SetDifficulty) -> Self {
-        Error::SetDifficultyToMessage(e)
+        TProxyError::SetDifficultyToMessage(e)
     }
 }
 
-impl<'a> From<std::convert::Infallible> for Error<'a> {
+impl<'a> From<std::convert::Infallible> for TProxyError<'a> {
     fn from(e: std::convert::Infallible) -> Self {
-        Error::Infallible(e)
+        TProxyError::Infallible(e)
     }
 }
 
-impl<'a> From<Mining<'a>> for Error<'a> {
+impl<'a> From<Mining<'a>> for TProxyError<'a> {
     fn from(e: Mining<'a>) -> Self {
-        Error::Sv2ProtocolError(e)
+        TProxyError::Sv2ProtocolError(e)
     }
 }
diff --git a/roles/translator/src/lib/mod.rs b/roles/translator/src/lib/mod.rs
index 2075e4569d..e4ab83b76e 100644
--- a/roles/translator/src/lib/mod.rs
+++ b/roles/translator/src/lib/mod.rs
@@ -1,7 +1,7 @@
 pub mod downstream_sv1;
 pub mod error;
 pub mod proxy;
-pub mod proxy_config;
 pub mod status;
+pub mod tproxy_config;
 pub mod upstream_sv2;
 pub mod utils;
diff --git a/roles/translator/src/lib/proxy/bridge.rs b/roles/translator/src/lib/proxy/bridge.rs
index 22aeaa18fe..fd4ed0e02f 100644
--- a/roles/translator/src/lib/proxy/bridge.rs
+++ b/roles/translator/src/lib/proxy/bridge.rs
@@ -15,8 +15,8 @@ use v1::{client_to_server::Submit, server_to_client, utils::HexU32Be};
 use super::super::{
     downstream_sv1::{DownstreamMessages, SetDownstreamTarget, SubmitShareWithChannelId},
     error::{
-        Error::{self, PoisonLock},
-        ProxyResult,
+        TProxyError::{self, PoisonLock},
+        TProxyResult,
     },
     status,
 };
@@ -114,7 +114,7 @@ impl Bridge {
     pub fn on_new_sv1_connection(
         &mut self,
         hash_rate: f32,
-    ) -> ProxyResult<'static, OpenSv1Downstream> {
+    ) -> TProxyResult<'static, OpenSv1Downstream> {
         match self.channel_factory.new_extended_channel(0, hash_rate, 0) {
             Ok(messages) => {
                 for message in messages {
@@ -141,12 +141,12 @@ impl Bridge {
                 }
             }
             Err(_) => {
-                return Err(Error::SubprotocolMining(
+                return Err(TProxyError::SubprotocolMining(
                     "Bridge: failed to open new extended channel".to_string(),
                 ))
             }
         };
-        Err(Error::SubprotocolMining(
+        Err(TProxyError::SubprotocolMining(
             "Bridge: Invalid mining message when opening downstream connection".to_string(),
         ))
     }
@@ -191,7 +191,7 @@ impl Bridge {
     fn handle_update_downstream_target(
         self_: Arc<Mutex<Self>>,
         new_target: SetDownstreamTarget,
-    ) -> ProxyResult<'static, ()> {
+    ) -> TProxyResult<'static, ()> {
         self_
             .safe_lock(|b| {
                 b.channel_factory
@@ -205,7 +205,7 @@ impl Bridge {
     async fn handle_submit_shares(
         self_: Arc<Mutex<Self>>,
         share: SubmitShareWithChannelId,
-    ) -> ProxyResult<'static, ()> {
+    ) -> TProxyResult<'static, ()> {
         let (tx_sv2_submit_shares_ext, target_mutex, tx_status) = self_
             .safe_lock(|s| {
                 (
@@ -276,16 +276,16 @@ impl Bridge {
         channel_id: u32,
         sv1_submit: Submit,
         version_rolling_mask: Option<HexU32Be>,
-    ) -> ProxyResult<'static, SubmitSharesExtended<'static>> {
+    ) -> TProxyResult<'static, SubmitSharesExtended<'static>> {
         let last_version = self
             .channel_factory
             .last_valid_job_version()
-            .ok_or(Error::RolesSv2Logic(RolesLogicError::NoValidJob))?;
+            .ok_or(TProxyError::RolesSv2Logic(RolesLogicError::NoValidJob))?;
         let version = match (sv1_submit.version_bits, version_rolling_mask) {
             // regarding version masking see https://github.com/slushpool/stratumprotocol/blob/master/stratum-extensions.mediawiki#changes-in-request-miningsubmit
             (Some(vb), Some(mask)) => (last_version & !mask.0) | (vb.0 & mask.0),
             (None, None) => last_version,
-            _ => return Err(Error::V1Protocol(v1::error::Error::InvalidSubmission)),
+            _ => return Err(TProxyError::V1Protocol(v1::error::Error::InvalidSubmission)),
         };
         let mining_device_extranonce: Vec<u8> = sv1_submit.extra_nonce2.into();
         let extranonce2 = mining_device_extranonce;
@@ -305,7 +305,7 @@ impl Bridge {
         self_: Arc<Mutex<Self>>,
         sv2_set_new_prev_hash: SetNewPrevHash<'static>,
         tx_sv1_notify: broadcast::Sender<server_to_client::Notify<'static>>,
-    ) -> Result<(), Error<'static>> {
+    ) -> TProxyResult<'static, ()> {
         while !crate::upstream_sv2::upstream::IS_NEW_JOB_HANDLED
             .load(std::sync::atomic::Ordering::SeqCst)
         {
@@ -403,7 +403,7 @@ impl Bridge {
         self_: Arc<Mutex<Self>>,
         sv2_new_extended_mining_job: NewExtendedMiningJob<'static>,
         tx_sv1_notify: broadcast::Sender<server_to_client::Notify<'static>>,
-    ) -> Result<(), Error<'static>> {
+    ) -> Result<(), TProxyError<'static>> {
         // convert to non segwit jobs so we dont have to depend if miner's support segwit or not
         self_
             .safe_lock(|s| {
@@ -427,7 +427,7 @@ impl Bridge {
                 .map_err(|_| PoisonLock)?;
 
             // last_p_hash is an Option<SetNewPrevHash> so we need to map to the correct error type to be handled
-            let last_p_hash = last_p_hash_option.ok_or(Error::RolesSv2Logic(
+            let last_p_hash = last_p_hash_option.ok_or(TProxyError::RolesSv2Logic(
                 RolesLogicError::JobIsNotFutureButPrevHashNotPresent,
             ))?;
 
diff --git a/roles/translator/src/lib/status.rs b/roles/translator/src/lib/status.rs
index 3ecbcc6342..2c77501363 100644
--- a/roles/translator/src/lib/status.rs
+++ b/roles/translator/src/lib/status.rs
@@ -1,4 +1,4 @@
-use crate::error::{self, Error};
+use crate::error::{self, TProxyError};
 
 #[derive(Debug)]
 pub enum Sender {
@@ -45,9 +45,9 @@ impl Clone for Sender {
 
 #[derive(Debug)]
 pub enum State<'a> {
-    DownstreamShutdown(Error<'a>),
-    BridgeShutdown(Error<'a>),
-    UpstreamShutdown(Error<'a>),
+    DownstreamShutdown(TProxyError<'a>),
+    BridgeShutdown(TProxyError<'a>),
+    UpstreamShutdown(TProxyError<'a>),
     Healthy(String),
 }
 
@@ -58,7 +58,7 @@ pub struct Status<'a> {
 
 async fn send_status(
     sender: &Sender,
-    e: error::Error<'static>,
+    e: error::TProxyError<'static>,
     outcome: error_handling::ErrorBranch,
 ) -> error_handling::ErrorBranch {
     match sender {
@@ -104,64 +104,81 @@ async fn send_status(
 // this is called by `error_handling::handle_result!`
 pub async fn handle_error(
     sender: &Sender,
-    e: error::Error<'static>,
+    e: error::TProxyError<'static>,
 ) -> error_handling::ErrorBranch {
     tracing::error!("Error: {:?}", &e);
     match e {
-        Error::VecToSlice32(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::ConfigError(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
+        TProxyError::VecToSlice32(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
         // Errors on bad CLI argument input.
-        Error::BadCliArgs => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::BadCliArgs => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Errors on bad `serde_json` serialize/deserialize.
-        Error::BadSerdeJson(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
-        // Errors on bad `toml` deserialize.
-        Error::BadTomlDeserialize(_) => {
+        TProxyError::BadSerdeJson(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // Errors from `binary_sv2` crate.
-        Error::BinarySv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::BinarySv2(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
         // Errors on bad noise handshake.
-        Error::CodecNoise(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::CodecNoise(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
         // Errors from `framing_sv2` crate.
-        Error::FramingSv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::FramingSv2(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
         //If the pool sends the tproxy an invalid extranonce
-        Error::InvalidExtranonce(_) => {
+        TProxyError::InvalidExtranonce(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // Errors on bad `TcpStream` connection.
-        Error::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Errors on bad `String` to `int` conversion.
-        Error::ParseInt(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::ParseInt(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
         // Errors from `roles_logic_sv2` crate.
-        Error::RolesSv2Logic(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
-        Error::UpstreamIncoming(_) => {
+        TProxyError::RolesSv2Logic(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
+        TProxyError::UpstreamIncoming(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // SV1 protocol library error
-        Error::V1Protocol(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
-        Error::SubprotocolMining(_) => {
+        TProxyError::V1Protocol(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
+        TProxyError::SubprotocolMining(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // Locking Errors
-        Error::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await,
+        TProxyError::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await,
         // Channel Receiver Error
-        Error::ChannelErrorReceiver(_) => {
+        TProxyError::ChannelErrorReceiver(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::TokioChannelErrorRecv(_) => {
+        TProxyError::TokioChannelErrorRecv(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
         // Channel Sender Errors
-        Error::ChannelErrorSender(_) => {
+        TProxyError::ChannelErrorSender(_) => {
+            send_status(sender, e, error_handling::ErrorBranch::Break).await
+        }
+        TProxyError::Uint256Conversion(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::Uint256Conversion(_) => {
+        TProxyError::SetDifficultyToMessage(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::SetDifficultyToMessage(_) => {
+        TProxyError::Infallible(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
-        Error::Infallible(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await,
-        Error::Sv2ProtocolError(ref inner) => {
+        TProxyError::Sv2ProtocolError(ref inner) => {
             match inner {
                 // dont notify main thread just continue
                 roles_logic_sv2::parsers::Mining::SubmitSharesError(_) => {
@@ -170,10 +187,10 @@ pub async fn handle_error(
                 _ => send_status(sender, e, error_handling::ErrorBranch::Break).await,
             }
         }
-        Error::TargetError(_) => {
+        TProxyError::TargetError(_) => {
             send_status(sender, e, error_handling::ErrorBranch::Continue).await
         }
-        Error::Sv1MessageTooLong => {
+        TProxyError::Sv1MessageTooLong => {
             send_status(sender, e, error_handling::ErrorBranch::Break).await
         }
     }
diff --git a/roles/translator/src/lib/proxy_config.rs b/roles/translator/src/lib/tproxy_config.rs
similarity index 98%
rename from roles/translator/src/lib/proxy_config.rs
rename to roles/translator/src/lib/tproxy_config.rs
index d0a8357261..b660eff063 100644
--- a/roles/translator/src/lib/proxy_config.rs
+++ b/roles/translator/src/lib/tproxy_config.rs
@@ -2,7 +2,7 @@ use key_utils::Secp256k1PublicKey;
 use serde::Deserialize;
 
 #[derive(Debug, Deserialize, Clone)]
-pub struct ProxyConfig {
+pub struct TProxyConfig {
     pub upstream_address: String,
     pub upstream_port: u16,
     pub upstream_authority_pubkey: Secp256k1PublicKey,
diff --git a/roles/translator/src/lib/upstream_sv2/diff_management.rs b/roles/translator/src/lib/upstream_sv2/diff_management.rs
index 830bf28d8f..9bc5be5753 100644
--- a/roles/translator/src/lib/upstream_sv2/diff_management.rs
+++ b/roles/translator/src/lib/upstream_sv2/diff_management.rs
@@ -1,7 +1,7 @@
 use super::Upstream;
 
 use super::super::{
-    error::{Error::PoisonLock, ProxyResult},
+    error::{TProxyError::PoisonLock, TProxyResult},
     upstream_sv2::{EitherFrame, Message, StdFrame},
 };
 use binary_sv2::u256_from_int;
@@ -12,7 +12,7 @@ use std::{sync::Arc, time::Duration};
 
 impl Upstream {
     /// this function checks if the elapsed time since the last update has surpassed the config
-    pub(super) async fn try_update_hashrate(self_: Arc<Mutex<Self>>) -> ProxyResult<'static, ()> {
+    pub(super) async fn try_update_hashrate(self_: Arc<Mutex<Self>>) -> TProxyResult<'static, ()> {
         let (channel_id_option, diff_mgmt, tx_frame) = self_
             .safe_lock(|u| {
                 (
@@ -22,9 +22,9 @@ impl Upstream {
                 )
             })
             .map_err(|_e| PoisonLock)?;
-        let channel_id = channel_id_option.ok_or(super::super::error::Error::RolesSv2Logic(
-            RolesLogicError::NotFoundChannelId,
-        ))?;
+        let channel_id = channel_id_option.ok_or(
+            super::super::error::TProxyError::RolesSv2Logic(RolesLogicError::NotFoundChannelId),
+        )?;
         let (timeout, new_hashrate) = diff_mgmt
             .safe_lock(|d| (d.channel_diff_update_interval, d.channel_nominal_hashrate))
             .map_err(|_e| PoisonLock)?;
@@ -39,7 +39,7 @@ impl Upstream {
         let frame: EitherFrame = either_frame.into();
 
         tx_frame.send(frame).await.map_err(|e| {
-            super::super::error::Error::ChannelErrorSender(
+            super::super::error::TProxyError::ChannelErrorSender(
                 super::super::error::ChannelSendError::General(e.to_string()),
             )
         })?;
diff --git a/roles/translator/src/lib/upstream_sv2/upstream.rs b/roles/translator/src/lib/upstream_sv2/upstream.rs
index f6d192f75e..2da5cf9c1f 100644
--- a/roles/translator/src/lib/upstream_sv2/upstream.rs
+++ b/roles/translator/src/lib/upstream_sv2/upstream.rs
@@ -1,11 +1,11 @@
 use crate::{
     downstream_sv1::Downstream,
     error::{
-        Error::{CodecNoise, InvalidExtranonce, PoisonLock, UpstreamIncoming},
-        ProxyResult,
+        TProxyError::{CodecNoise, InvalidExtranonce, PoisonLock, UpstreamIncoming},
+        TProxyResult,
     },
-    proxy_config::UpstreamDifficultyConfig,
     status,
+    tproxy_config::UpstreamDifficultyConfig,
     upstream_sv2::{EitherFrame, Message, StdFrame, UpstreamConnection},
 };
 use async_channel::{Receiver, Sender};
@@ -124,7 +124,7 @@ impl Upstream {
         tx_status: status::Sender,
         target: Arc<Mutex<Vec<u8>>>,
         difficulty_config: Arc<Mutex<UpstreamDifficultyConfig>>,
-    ) -> ProxyResult<'static, Arc<Mutex<Self>>> {
+    ) -> TProxyResult<'static, Arc<Mutex<Self>>> {
         // Connect to the SV2 Upstream role retry connection every 5 seconds.
         let socket = loop {
             match TcpStream::connect(address).await {
@@ -179,7 +179,7 @@ impl Upstream {
         self_: Arc<Mutex<Self>>,
         min_version: u16,
         max_version: u16,
-    ) -> ProxyResult<'static, ()> {
+    ) -> TProxyResult<'static, ()> {
         // Get the `SetupConnection` message with Mining Device information (currently hard coded)
         let setup_connection = Self::get_setup_connection_message(min_version, max_version, false)?;
         let mut connection = self_
@@ -257,7 +257,7 @@ impl Upstream {
     /// Parses the incoming SV2 message from the Upstream role and routes the message to the
     /// appropriate handler.
     #[allow(clippy::result_large_err)]
-    pub fn parse_incoming(self_: Arc<Mutex<Self>>) -> ProxyResult<'static, ()> {
+    pub fn parse_incoming(self_: Arc<Mutex<Self>>) -> TProxyResult<'static, ()> {
         let clone = self_.clone();
         let (
             tx_frame,
@@ -300,7 +300,7 @@ impl Upstream {
                 let message_type =
                     incoming
                         .get_header()
-                        .ok_or(super::super::error::Error::FramingSv2(
+                        .ok_or(super::super::error::TProxyError::FramingSv2(
                             framing_sv2::Error::ExpectedSv2Frame,
                         ));
 
@@ -337,7 +337,7 @@ impl Upstream {
                         handle_result!(
                             tx_status,
                             tx_frame.send(frame).await.map_err(|e| {
-                                super::super::error::Error::ChannelErrorSender(
+                                super::super::error::TProxyError::ChannelErrorSender(
                                     super::super::error::ChannelSendError::General(e.to_string()),
                                 )
                             })
@@ -439,26 +439,29 @@ impl Upstream {
     #[allow(clippy::result_large_err)]
     fn get_job_id(
         self_: &Arc<Mutex<Self>>,
-    ) -> Result<Result<u32, super::super::error::Error<'static>>, super::super::error::Error<'static>>
-    {
+    ) -> Result<
+        Result<u32, super::super::error::TProxyError<'static>>,
+        super::super::error::TProxyError<'static>,
+    > {
         self_
             .safe_lock(|s| {
                 if s.is_work_selection_enabled() {
                     s.last_job_id
-                        .ok_or(super::super::error::Error::RolesSv2Logic(
+                        .ok_or(super::super::error::TProxyError::RolesSv2Logic(
                             RolesLogicError::NoValidTranslatorJob,
                         ))
                 } else {
-                    s.job_id.ok_or(super::super::error::Error::RolesSv2Logic(
-                        RolesLogicError::NoValidJob,
-                    ))
+                    s.job_id
+                        .ok_or(super::super::error::TProxyError::RolesSv2Logic(
+                            RolesLogicError::NoValidJob,
+                        ))
                 }
             })
             .map_err(|_e| PoisonLock)
     }
 
     #[allow(clippy::result_large_err)]
-    pub fn handle_submit(self_: Arc<Mutex<Self>>) -> ProxyResult<'static, ()> {
+    pub fn handle_submit(self_: Arc<Mutex<Self>>) -> TProxyResult<'static, ()> {
         let clone = self_.clone();
         let (tx_frame, receiver, tx_status) = clone
             .safe_lock(|s| {
@@ -478,7 +481,7 @@ impl Upstream {
                 let channel_id = self_
                     .safe_lock(|s| {
                         s.channel_id
-                            .ok_or(super::super::error::Error::RolesSv2Logic(
+                            .ok_or(super::super::error::TProxyError::RolesSv2Logic(
                                 RolesLogicError::NotFoundChannelId,
                             ))
                     })
@@ -499,7 +502,7 @@ impl Upstream {
                 handle_result!(
                     tx_status,
                     tx_frame.send(frame).await.map_err(|e| {
-                        super::super::error::Error::ChannelErrorSender(
+                        super::super::error::TProxyError::ChannelErrorSender(
                             super::super::error::ChannelSendError::General(e.to_string()),
                         )
                     })
@@ -521,7 +524,7 @@ impl Upstream {
         min_version: u16,
         max_version: u16,
         is_work_selection_enabled: bool,
-    ) -> ProxyResult<'static, SetupConnection<'static>> {
+    ) -> TProxyResult<'static, SetupConnection<'static>> {
         let endpoint_host = "0.0.0.0".to_string().into_bytes().try_into()?;
         let vendor = String::new().try_into()?;
         let hardware_version = String::new().try_into()?;
diff --git a/roles/translator/src/lib/upstream_sv2/upstream_connection.rs b/roles/translator/src/lib/upstream_sv2/upstream_connection.rs
index 49392b78e4..b563ac91e2 100644
--- a/roles/translator/src/lib/upstream_sv2/upstream_connection.rs
+++ b/roles/translator/src/lib/upstream_sv2/upstream_connection.rs
@@ -1,4 +1,4 @@
-use super::{super::error::ProxyResult, EitherFrame, StdFrame};
+use super::{super::error::TProxyResult, EitherFrame, StdFrame};
 use async_channel::{Receiver, Sender};
 
 /// Handles the sending and receiving of messages to and from an SV2 Upstream role (most typically
@@ -18,10 +18,10 @@ pub struct UpstreamConnection {
 
 impl UpstreamConnection {
     /// Send a SV2 message to the Upstream role
-    pub async fn send(&mut self, sv2_frame: StdFrame) -> ProxyResult<'static, ()> {
+    pub async fn send(&mut self, sv2_frame: StdFrame) -> TProxyResult<'static, ()> {
         let either_frame = sv2_frame.into();
         self.sender.send(either_frame).await.map_err(|e| {
-            super::super::error::Error::ChannelErrorSender(
+            super::super::error::TProxyError::ChannelErrorSender(
                 super::super::error::ChannelSendError::General(e.to_string()),
             )
         })?;
diff --git a/roles/translator/src/main.rs b/roles/translator/src/main.rs
index c1307a5a2f..014e096938 100644
--- a/roles/translator/src/main.rs
+++ b/roles/translator/src/main.rs
@@ -2,10 +2,8 @@
 mod args;
 mod lib;
 
-use args::Args;
-use error::{Error, ProxyResult};
-use lib::{downstream_sv1, error, proxy, proxy_config, status, upstream_sv2};
-use proxy_config::ProxyConfig;
+use args::process_cli_args;
+use lib::{downstream_sv1, error, proxy, status, tproxy_config, upstream_sv2};
 use roles_logic_sv2::utils::Mutex;
 
 use async_channel::{bounded, unbounded};
@@ -21,19 +19,6 @@ use v1::server_to_client;
 
 use crate::status::{State, Status};
 use tracing::{debug, error, info};
-/// Process CLI args, if any.
-#[allow(clippy::result_large_err)]
-fn process_cli_args<'a>() -> ProxyResult<'a, ProxyConfig> {
-    let args = match Args::from_args() {
-        Ok(cfg) => cfg,
-        Err(help) => {
-            error!("{}", help);
-            return Err(Error::BadCliArgs);
-        }
-    };
-    let config_file = std::fs::read_to_string(args.config_path)?;
-    Ok(toml::from_str::<ProxyConfig>(&config_file)?)
-}
 
 #[tokio::main]
 async fn main() {