gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-depolymerization] branch master updated (ee9c608 -> a02daa4)


From: gnunet
Subject: [taler-depolymerization] branch master updated (ee9c608 -> a02daa4)
Date: Fri, 04 Mar 2022 21:22:52 +0100

This is an automated email from the git hooks/post-receive script.

antoine pushed a change to branch master
in repository depolymerization.

    from ee9c608  eth-wire: reuse rpc connection for notifications
     new 1e93728  Improve documentation
     new a02daa4  Improve config parsing

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |   1 +
 Cargo.lock                                         |  85 ++++++-----
 README.md                                          | 142 ++++++++++++++----
 btc-wire/Cargo.toml                                |   6 +-
 btc-wire/README.md                                 |  59 ++------
 btc-wire/src/bin/btc-wire-utils.rs                 |  25 ++--
 btc-wire/src/config.rs                             |  81 +++++------
 btc-wire/src/lib.rs                                |  77 +++++++---
 btc-wire/src/loops/worker.rs                       |   6 +-
 btc-wire/src/main.rs                               |  25 ++--
 btc-wire/src/rpc.rs                                |   5 +-
 btc-wire/src/rpc_utils.rs                          |  23 ++-
 common/Cargo.toml                                  |  13 +-
 common/src/config.rs                               | 159 ++++++++-------------
 docs/taler-btc.conf                                |  17 +++
 docs/taler-eth.conf                                |  17 +++
 eth-wire/Cargo.toml                                |   6 +-
 eth-wire/README.md                                 |  38 +----
 eth-wire/src/bin/eth-wire-utils.rs                 |  34 ++---
 eth-wire/src/lib.rs                                |  59 ++++++--
 eth-wire/src/loops/worker.rs                       |   8 +-
 eth-wire/src/main.rs                               |  63 ++------
 eth-wire/src/rpc.rs                                |  18 ++-
 eth-wire/src/rpc_utils.rs                          |  20 +++
 instrumentation/Cargo.toml                         |   7 +-
 instrumentation/src/btc.rs                         |   9 +-
 instrumentation/src/eth.rs                         |  24 +---
 instrumentation/src/main.rs                        |   8 +-
 test/btc/config.sh                                 |   4 +-
 test/btc/wire.sh                                   |   2 +-
 test/common.sh                                     |   7 +-
 .../conf/{bitcoin_auth.conf => bitcoin_auth0.conf} |   0
 wire-gateway/Cargo.toml                            |  12 +-
 wire-gateway/src/main.rs                           |  35 +++--
 34 files changed, 587 insertions(+), 508 deletions(-)
 create mode 100644 docs/taler-btc.conf
 create mode 100644 docs/taler-eth.conf
 create mode 100644 eth-wire/src/rpc_utils.rs
 rename test/conf/{bitcoin_auth.conf => bitcoin_auth0.conf} (100%)

diff --git a/.gitignore b/.gitignore
index 321b957..89a34eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ log
 /docs/*
 !/docs/*.docx
 !/docs/*.tex
+!/docs/*.conf
 !/docs/media
 /tmp
 taler.conf
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 4ddd828..b852b39 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,9 +10,14 @@ checksum = 
"f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "ahash"
-version = "0.4.7"
+version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+dependencies = [
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
 
 [[package]]
 name = "aho-corasick"
@@ -124,7 +129,7 @@ dependencies = [
  "base64",
  "bech32",
  "bitcoin",
- "clap 3.1.3",
+ "clap 3.1.5",
  "common",
  "criterion",
  "hex",
@@ -206,9 +211,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.1.3"
+version = "3.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "86f8c0e2a6b902acc18214e24a6935cdaf8a8e34231913d4404dcaee659f65a1"
+checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312"
 dependencies = [
  "atty",
  "bitflags",
@@ -218,14 +223,14 @@ dependencies = [
  "os_str_bytes",
  "strsim",
  "termcolor",
- "textwrap 0.14.2",
+ "textwrap 0.15.0",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "3.1.2"
+version = "3.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "01d42c94ce7c2252681b5fed4d3627cc807b13dfc033246bd05d5b252399000e"
+checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -234,6 +239,16 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "clap_mangen"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "0649fb4156bbd7306896025005596033879a2051f9a3aa7416ab915df1f8fdac"
+dependencies = [
+ "clap 3.1.5",
+ "roff",
+]
+
 [[package]]
 name = "common"
 version = "0.1.0"
@@ -470,12 +485,9 @@ dependencies = [
 
 [[package]]
 name = "dlv-list"
-version = "0.2.3"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b"
-dependencies = [
- "rand",
-]
+checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
 
 [[package]]
 name = "either"
@@ -497,7 +509,7 @@ dependencies = [
 name = "eth-wire"
 version = "0.1.0"
 dependencies = [
- "clap 3.1.3",
+ "clap 3.1.5",
  "common",
  "ethereum-types",
  "hex",
@@ -726,19 +738,13 @@ checksum = 
"eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
 
 [[package]]
 name = "hashbrown"
-version = "0.9.1"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 dependencies = [
  "ahash",
 ]
 
-[[package]]
-name = "hashbrown"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
-
 [[package]]
 name = "heck"
 version = "0.4.0"
@@ -872,7 +878,7 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
 dependencies = [
  "autocfg",
- "hashbrown 0.11.2",
+ "hashbrown",
 ]
 
 [[package]]
@@ -890,7 +896,8 @@ version = "0.1.0"
 dependencies = [
  "bitcoin",
  "btc-wire",
- "clap 3.1.3",
+ "clap 3.1.5",
+ "clap_mangen",
  "common",
  "eth-wire",
  "ethereum-types",
@@ -1089,9 +1096,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
 
 [[package]]
 name = "oorandom"
@@ -1101,12 +1108,12 @@ checksum = 
"0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
 [[package]]
 name = "ordered-multimap"
-version = "0.3.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485"
+checksum = "7b476c5fc0aad16f8b8d74e7df9da1813731fae300f7a923713c4c591905ff50"
 dependencies = [
  "dlv-list",
- "hashbrown 0.9.1",
+ "hashbrown",
 ]
 
 [[package]]
@@ -1453,11 +1460,17 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "roff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
+
 [[package]]
 name = "rust-ini"
-version = "0.17.0"
+version = "0.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22"
+checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
 dependencies = [
  "cfg-if",
  "ordered-multimap",
@@ -1725,9 +1738,9 @@ dependencies = [
 
 [[package]]
 name = "termcolor"
-version = "1.1.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
 dependencies = [
  "winapi-util",
 ]
@@ -1743,9 +1756,9 @@ dependencies = [
 
 [[package]]
 name = "textwrap"
-version = "0.14.2"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
+checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
 
 [[package]]
 name = "thiserror"
@@ -2171,7 +2184,7 @@ name = "wire-gateway"
 version = "0.1.0"
 dependencies = [
  "bitcoin",
- "clap 3.1.3",
+ "clap 3.1.5",
  "common",
  "deadpool-postgres",
  "ethereum-types",
diff --git a/README.md b/README.md
index bd43817..903deee 100644
--- a/README.md
+++ b/README.md
@@ -2,41 +2,102 @@
 
 ## Project structure
 
-- **wire-gateway**: [Taler Wire Gateway HTTP 
API](https://docs.taler.net/core/api-wire.html) server
-- **btc-wire**: Taler wire implementation for 
[bitcoincore](https://bitcoincore.org/en/about/) node
-- **eth-wire**: Taler wire implementation for 
[go-ethereum](https://geth.ethereum.org/) node
+- **wire-gateway**:
+  [Taler Wire Gateway HTTP API](https://docs.taler.net/core/api-wire.html)
+  server
+- **btc-wire**: Taler wire implementation for
+  [bitcoincore](https://bitcoincore.org/en/about/) node
+- **eth-wire**: Taler wire implementation for
+  [go-ethereum](https://geth.ethereum.org/) node
 - **uri-pack**: Efficient probabilistic binary encoding for URI
+- **db**: Database schemas
 - **docs**: Documentation files
 - **test**: Test scripts
+- **instrumentation**: Instrumentation test tool
 
-## Install
+## Install from source
+
+Cargo version 1.16.1 or above is required. You can get cargo from your
+distribution package manager or from [rustup.rs](https://rustup.rs/).
 
 ```
+git clone https://git.taler.net/depolymerization.git/
+cd depolymerization
 make install
 ```
 
-Read adapter specific documentation to run depolymerizer:
+To also install test tools run: `make install_test`.
 
-- [BTC](btc-wire/README.md)
-- [ETH](eth-wire/README.md)
+## Configuration
 
+The configuration is based on
+[taler.conf](https://docs.taler.net/manpages/taler.conf.5.html).
 
-## Configuration
+You can find filled configurations for each implementation:
 
-The configuration is based on 
[taler.conf](https://docs.taler.net/manpages/taler.conf.5.html).
+- [btc-wire](docs/taler-btc.conf)
+- [eth-wire](docs/taler-eth.conf)
+
+### Initialization
 
 This is the minimal required config for initialization.
 
-``` ini
-# taler.conf - required config (fill all ___)
+```ini
+# taler.conf - (fill all ___)
 [taler]
-CURRENCY = ___ 
+# Exchange currency
+CURRENCY = ___
 
 [exchange]
-BASE_URL = https://___
+# Exchange base url
+BASE_URL = ___
+
+[depolymerizer-___]
+# Postgres connection URL
+DB_URL   = ___
+# Wire payto URL
+# PAYTO = ___
+```
+
+`PAYTO` is to be added after wallet initialization.
+
+### btc-wire
+
+btc-wire will automatically read the bitcoin configuration file to connect to
+the RPC server. Two flags are mandatory:
+
+- `txindex=1`: btc-wire need access to transaction not linked to the wire 
wallet
+- `maxtxfee=?`: bitcoin transactions fees can exceed taler wire fees, putting
+  your wire in bankruptcy. You must specify an acceptable transaction fee cap.
+
+```ini
+[depolymerizer-bitcoin]
+# Datadir or configuration file path
+CONF_PATH     = ~/.bitcoin
+# Number of blocks to consider a transactions durable
+CONFIRMATION = 6
+# Amount to keep when bouncing malformed credit
+BOUNCE_FEE   = BTC:0.00001
+```
+
+### eth-wire
+
+```ini
+[depolymerizer-bitcoin]
+# Datadir or ipc file path
+IPC_PATH      = ~/.ethereum/geth/geth.ipc
+# Number of blocks to consider a transactions durable
+CONFIRMATION = 24
+# Amount to keep when bouncing malformed credit
+BOUNCE_FEE   = ETH:0.00001
+```
+
+### Wire gateway
 
+```ini
 [depolymerizer-___]
-DB_URL   = postgres://___
+PORT          = 8080
+UNIXPATH      =
 ```
 
 ### Process lifetime
@@ -46,7 +107,7 @@ stability (ex. fix memory fragmentation). It is possible to 
configure lifetime
 that trigger graceful shutdown every time a specific amount of work have been
 done.
 
-``` ini
+```ini
 [depolymerizer-___]
 # Number of requests to serve before gateway shutdown (0 mean never)
 HTTP_LIFETIME = 0
@@ -58,24 +119,47 @@ WIRE_LIFETIME = 0
 
 When a transaction is sent with a fee too small compared to other transaction,
 it can take an unlimited amount of time for this transaction to be mined. It is
-possible to replace this transaction with another transaction with more fees. 
+possible to replace this transaction with another transaction with more fees.
 Depolymerizer can be configured to do this automatically:
 
-``` ini
+```ini
 [depolymerizer-___]
 # Delay in seconds before bumping an unconfirmed transaction fee (0 mean never)
 BUMP_DELAY = 0
 ```
 
-Modules have specific configuration:
+## Getting started
+
+#### btc-wire
 
-- [wire-gateway](wire-gateway/README.md#Configuration)
-- [btc-wire](btc-wire/README.md#Configuration)
+[Bitcoind](https://bitcoincore.org/) version 22.\* is required
+
+1. Write configuration files
+2. Start bitcoind
+3. Start PostgreSQL
+4. Initialize database `btc-wire initdb`
+5. Initialize wallet `btc-wire initwallet`
+6. Update configuration files with wallet info
+7. Run wire-gateway `wire-gateway`
+8. Run btc-wire `btc-wire`
+
+#### eth-wire
+
+[Geth](https://geth.ethereum.org/) version 1.10.\* is required
+
+1. Write configuration files
+2. Start geth
+3. Start PostgreSQL
+4. Initialize database `eth-wire initdb`
+5. Initialize wallet `eth-wire initwallet`
+6. Update configuration files with wallet info
+7. Run wire-gateway `wire-gateway`
+8. Run eth-wire `eth-wire`
 
 ## Security
 
-Depolymerizer only use encrypted wallet, and provide an easy way to create
-them. However, it is the administrator responsibility to backup its wallet and
+Depolymerizer only use encrypted wallet, and provide an easy way to create 
them.
+However, it is the administrator responsibility to backup its wallet and
 password.
 
 Only the wire adapter need to have the password stored in its environnement.
@@ -83,16 +167,18 @@ Only the wire adapter need to have the password stored in 
its environnement.
 ## Test
 
 The following binaries need to be in the local user PATH:
+
 - `pg_ctl` and `psql` from PostgreSQL
 - `geth` from [go-ethereum](https://geth.ethereum.org/downloads/)
-- `bitcoind` and `bitcoin-cli` from 
[bitcoincore](https://bitcoincore.org/en/download/)
--  `taler-config` and `taler-exchange-wire-gateway-client` from the
-[Taler exchange repository](https://git.taler.net/exchange.git/)
+- `bitcoind` and `bitcoin-cli` from
+  [bitcoincore](https://bitcoincore.org/en/download/)
+- `taler-config` and `taler-exchange-wire-gateway-client` from the
+  [Taler exchange repository](https://git.taler.net/exchange.git/)
 
 You can use the [prepare](script/prepare.sh) script to downloads and extract
-blockchain binaries and find the path of the local postgres
-installation. However taler binaries need to be compiled from source for now.
+blockchain binaries and find the path of the local postgres installation.
+However taler binaries need to be compiled from source for now.
 
 ```
 make test
-```
\ No newline at end of file
+```
diff --git a/btc-wire/Cargo.toml b/btc-wire/Cargo.toml
index 88d33a0..6c6c93a 100644
--- a/btc-wire/Cargo.toml
+++ b/btc-wire/Cargo.toml
@@ -16,12 +16,12 @@ bitcoin = { version = "0.27.1", features = [
     "use-serde",
 ], default-features = false }
 # Cli args parser
-clap = { version = "3.1.0", features = ["derive"] }
+clap = { version = "3.1.5", features = ["derive"] }
 # Bech32 encoding and decoding
 bech32 = "0.8.1"
 # Serialization library
 serde = { version = "1.0.136", features = ["derive"] }
-serde_json = "1.0.78"
+serde_json = "1.0.79"
 serde_repr = "0.1.7"
 # Error macros
 thiserror = "1.0.30"
@@ -31,7 +31,7 @@ base64 = "0.13.0"
 # Common lib
 common = { path = "../common" }
 # Ini parser
-rust-ini = "0.17.0"
+rust-ini = "0.18.0"
 # Hexadecimal encoding
 hex = "0.4.3"
 
diff --git a/btc-wire/README.md b/btc-wire/README.md
index d9d7a95..c887fd4 100644
--- a/btc-wire/README.md
+++ b/btc-wire/README.md
@@ -1,44 +1,7 @@
 # btc-wire
 
-btc-wire is taler wire adapter for 
[bitcoincore](https://bitcoincore.org/en/about/) node
-
-## Bitcoincore compatibility
-
-Bitcoind version 22.* is required
-
-## Install 
-
-`cargo install --path btc-wire`
-
-## Configuration
-
-### taler.conf
-
-The configuration is based on 
[taler.conf](https://docs.taler.net/manpages/taler.conf.5.html)
-
-``` ini
-# taler.conf - btc-wire default config
-[depolymerizer-bitcoin]
-DATA_DIR     =
-CONFIRMATION = 6
-BOUNCE_FEE   = BTC:0.00001
-```
-
-### bitcoin.conf
-
-btc-wire will automatically read the bitcoin configuration file to connect to
-the RPC server, `txindex=1` and `maxtxfee` are mandatory.
-
-## Getting Started
-
-1. Write configuration files
-2. Start bitcoind
-3. Start PostgreSQL
-4. Initialize database `btc-wire initdb`
-5. Initialize wallet `btc-wire initwallet`
-6. Update configuration files with wallet info
-7. Run wire-gateway `wire-gateway`
-8. Run btc-wire `btc-wire`
+btc-wire is taler wire adapter for
+[bitcoincore](https://bitcoincore.org/en/about/) node
 
 ## Deposit metadata format
 
@@ -47,17 +10,17 @@ addresses to encode the reserve public key as metadata into 
a common bitcoin
 transaction.
 
 A single segwit address can contain 20B of chosen data and the reserve pub key
-is 32B. We use two fake adresses consisting of the two key half prepended
-with the same random pattern, at the exception of the first bit with must be 0
-for the first half and 1 for the second one. You must then send a single
-transaction with the three addresses as recipients.
+is 32B. We use two fake adresses consisting of the two key half prepended with
+the same random pattern, at the exception of the first bit with must be 0 for
+the first half and 1 for the second one. You must then send a single 
transaction
+with the three addresses as recipients.
 
-Segwit addresses are encoded using a bitcoin specific format: 
+Segwit addresses are encoded using a bitcoin specific format:
 [bech32](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)
 
 As a few lines of code can carry more meaning that many words, you can find a
 [simple rust example](src/bin/segwit-demo.rs) in this project and run it with
-`make segwit_demo`. 
+`make segwit_demo`.
 
 ```
 Ⅰ - Parse payto uri
@@ -100,5 +63,7 @@ Make sure the amount show 0.10000588 BTC, else you have to 
change the base unit
 
 ### Stuck transaction
 
-We resolve stuck transaction by always sending replaceable transaction
-using [BIP 
125](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki).
\ No newline at end of file
+We resolve stuck transaction by always sending replaceable transaction using
+[BIP 125](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki).
+
+TODO
diff --git a/btc-wire/src/bin/btc-wire-utils.rs 
b/btc-wire/src/bin/btc-wire-utils.rs
index ae6a000..c29874f 100644
--- a/btc-wire/src/bin/btc-wire-utils.rs
+++ b/btc-wire/src/bin/btc-wire-utils.rs
@@ -18,15 +18,11 @@ use std::path::PathBuf;
 use bitcoin::{Address, Amount, BlockHash, Network};
 use btc_wire::{
     config::BitcoinConfig,
+    load_taler_config,
     rpc::{Category, Rpc},
-    rpc_utils::default_data_dir,
 };
 use clap::StructOpt;
-use common::{
-    config::{Config, CoreConfig},
-    postgres::NoTls,
-    rand_slice,
-};
+use common::{postgres::NoTls, rand_slice};
 
 /// btc-wire test utils
 #[derive(clap::Parser, Debug)]
@@ -84,15 +80,12 @@ pub fn auto_wallet(rpc: &mut Rpc, config: &BitcoinConfig, 
name: &str) -> (Rpc, A
 fn main() {
     common::log::init();
     let args = Args::parse();
-    let config = args
-        .config
-        .map(|path| CoreConfig::load_taler_config(Some(&path), Some("BTC")));
-    let data_dir: PathBuf = config
-        .as_ref()
-        .and_then(|it| it.data_dir.clone())
-        .or(args.datadir)
-        .unwrap_or_else(default_data_dir);
-    let btc_config = BitcoinConfig::load(data_dir).unwrap();
+    let taler_config = load_taler_config(args.config.as_deref());
+    let btc_config = BitcoinConfig::load(
+        args.datadir.unwrap_or(taler_config.custom),
+        &taler_config.currency,
+    )
+    .unwrap();
     let mut rpc = Rpc::common(&btc_config).unwrap();
 
     match args.cmd {
@@ -128,7 +121,7 @@ fn main() {
         }
         Cmd::Resetdb => {
             let hash: BlockHash = rpc.get_genesis().unwrap();
-            let mut db = config.unwrap().db_config.connect(NoTls).unwrap();
+            let mut db = taler_config.db_config.connect(NoTls).unwrap();
             let mut tx = db.transaction().unwrap();
             // Clear transaction tables and reset state
             tx.execute("DELETE FROM tx_in", &[]).unwrap();
diff --git a/btc-wire/src/config.rs b/btc-wire/src/config.rs
index c8eb5dd..54fdadc 100644
--- a/btc-wire/src/config.rs
+++ b/btc-wire/src/config.rs
@@ -22,48 +22,36 @@ use std::{
 use bitcoin::Network;
 use common::log::{fail, OrFail};
 
-pub const WIRE_WALLET_NAME: &str = "wire";
-
-/// Default chain dir 
<https://github.com/bitcoin/bitcoin/blob/master/doc/files.md#data-directory-location>
-fn chain_dir(network: Network) -> &'static str {
-    match network {
-        Network::Bitcoin => "main",
-        Network::Testnet => "testnet3",
-        Network::Regtest => "regtest",
-        Network::Signet => "signet",
-    }
-}
+use crate::{
+    check_network_currency,
+    rpc_utils::{chain_dir, rpc_port},
+};
 
-/// Default rpc port 
<https://github.com/bitcoin/bitcoin/blob/master/share/examples/bitcoin.conf>
-fn rpc_port(network: Network) -> u16 {
-    match network {
-        Network::Bitcoin => 8332,
-        Network::Testnet => 18332,
-        Network::Regtest => 18443,
-        Network::Signet => 38333,
-    }
-}
+pub const WIRE_WALLET_NAME: &str = "wire";
 
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub enum BtcAuth {
-    Cookie,
+    Cookie(PathBuf),
     Auth(String),
 }
 
 /// Bitcoin config relevant for btc-wire
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub struct BitcoinConfig {
     pub network: Network,
-    pub dir: PathBuf,
     pub addr: SocketAddr,
     pub auth: BtcAuth,
-    pub cookie_path: String,
 }
 
 impl BitcoinConfig {
-    /// Load from bitcoin data_dir
-    pub fn load(data_dir: impl AsRef<Path>) -> Result<Self, ini::Error> {
-        let conf = 
ini::Ini::load_from_file(data_dir.as_ref().join("bitcoin.conf"))?;
+    /// Load from bitcoin path
+    pub fn load(path: impl AsRef<Path>, currency: &str) -> Result<Self, 
ini::Error> {
+        let path = path.as_ref();
+        let conf = if path.is_dir() {
+            ini::Ini::load_from_file(path.join("bitcoin.conf"))
+        } else {
+            ini::Ini::load_from_file(path)
+        }?;
 
         let main = conf.general_section();
 
@@ -85,6 +73,8 @@ impl BitcoinConfig {
             Network::Bitcoin
         };
 
+        check_network_currency(network, currency);
+
         let section = match network {
             Network::Bitcoin => Some(main),
             Network::Testnet => conf.section(Some("test")),
@@ -100,9 +90,8 @@ impl BitcoinConfig {
         };
 
         let addr = if let Some(addr) = section.and_then(|s| s.get("rpcbind")) {
-            SocketAddr::from_str(addr).or_fail(|_| {
-                "bitcoin config value 'rpcbind' is not a valid socket 
address".into()
-            })
+            SocketAddr::from_str(addr)
+                .or_fail(|_| "bitcoin config value 'rpcbind' is not a valid 
socket address".into())
         } else {
             ([127, 0, 0, 1], port).into()
         };
@@ -115,24 +104,30 @@ impl BitcoinConfig {
         } else if let (Some(login), Some(passwd)) = (main.get("rpcuser"), 
main.get("rpcpassword")) {
             BtcAuth::Auth(format!("{}:{}", login, passwd))
         } else {
-            BtcAuth::Cookie
+            let cookie_file = if let Some(path) = section.and_then(|s| 
s.get("rpccookiefile")) {
+                path
+            } else if let Some(path) = main.get("rpccookiefile") {
+                path
+            } else {
+                ".cookie"
+            }
+            .to_string();
+            let data_dir = if let Some(path) = section.and_then(|s| 
s.get("datadir")) {
+                PathBuf::from(path)
+            } else if let Some(path) = main.get("datadir") {
+                PathBuf::from(path)
+            } else if path.is_file() {
+                path.parent().unwrap().to_path_buf()
+            } else {
+                path.to_path_buf()
+            };
+            
BtcAuth::Cookie(data_dir.join(chain_dir(network)).join(cookie_file))
         };
 
-        let cookie_path = if let Some(path) = section.and_then(|s| 
s.get("rpccookiefile")) {
-            path
-        } else if let Some(path) = main.get("rpccookiefile") {
-            path
-        } else {
-            ".cookie"
-        }
-        .to_string();
-
         Ok(Self {
             network,
             addr,
-            dir: data_dir.as_ref().join(chain_dir(network)),
             auth,
-            cookie_path,
         })
     }
 }
diff --git a/btc-wire/src/lib.rs b/btc-wire/src/lib.rs
index 78f0c51..d632477 100644
--- a/btc-wire/src/lib.rs
+++ b/btc-wire/src/lib.rs
@@ -1,3 +1,4 @@
+use std::path::{Path, PathBuf};
 /*
   This file is part of TALER
   Copyright (C) 2022 Taler Systems SA
@@ -17,7 +18,10 @@ use std::{str::FromStr, sync::atomic::AtomicU32};
 
 use bitcoin::{hashes::hex::FromHex, Address, Amount, Network, Txid};
 use common::api_common::Amount as TalerAmount;
-use common::config::BtcConfig;
+use common::config::TalerConfig;
+use common::log::{fail, OrFail};
+use common::postgres;
+use common::url::Url;
 use config::BitcoinConfig;
 use rpc::{Category, Rpc, Transaction};
 use rpc_utils::{default_data_dir, segwit_min_amount, sender_address};
@@ -143,39 +147,68 @@ impl Rpc {
 const DEFAULT_BOUNCE_FEE: &str = "BTC:0.00001";
 const DEFAULT_CONFIRMATION: u16 = 6;
 
-fn config_bounce_fee(config: &BtcConfig) -> Amount {
-    let config = config.bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE);
-    TalerAmount::from_str(config)
-        .ok()
-        .and_then(|a| taler_to_btc(&a).ok())
-        .expect("config value BOUNCE_FEE is no a valid bitcoin amount")
-}
-
 pub struct WireState {
     pub confirmation: AtomicU32,
     pub max_confirmation: u32,
-    pub config: BtcConfig,
     pub btc_config: BitcoinConfig,
     pub bounce_fee: Amount,
+    pub lifetime: Option<u32>,
+    pub bump_delay: Option<u32>,
+    pub base_url: Url,
+    pub db_config: postgres::Config,
 }
 
 impl WireState {
-    pub fn from_taler_config(config: BtcConfig) -> Self {
-        let data_dir = config
-            .core
-            .data_dir
-            .as_ref()
-            .cloned()
-            .unwrap_or_else(default_data_dir);
-        let btc_config =
-            BitcoinConfig::load(&data_dir).expect("Failed to read bitcoin 
configuration file");
-        let init_confirmation = 
config.confirmation.unwrap_or(DEFAULT_CONFIRMATION) as u32;
+    pub fn load_taler_config(file: Option<&Path>) -> Self {
+        let taler_config = load_taler_config(file);
+        let btc_config = BitcoinConfig::load(taler_config.custom, 
&taler_config.currency)
+            .expect("Failed to read bitcoin configuration file");
+        let init_confirmation = 
taler_config.confirmation.unwrap_or(DEFAULT_CONFIRMATION) as u32;
         Self {
             confirmation: AtomicU32::new(init_confirmation),
             max_confirmation: init_confirmation * 2,
-            bounce_fee: config_bounce_fee(&config),
-            config,
             btc_config,
+            bounce_fee: config_bounce_fee(&taler_config.bounce_fee),
+            lifetime: taler_config.wire_lifetime,
+            bump_delay: taler_config.bump_delay,
+            base_url: taler_config.base_url,
+            db_config: taler_config.db_config,
+        }
+    }
+}
+
+// Load taler config with btc-wire specific config
+pub fn load_taler_config(file: Option<&Path>) -> TalerConfig<PathBuf> {
+    TalerConfig::load_with_custom(file, |dep| {
+        common::config::path(dep, "CONF_PATH").unwrap_or_else(default_data_dir)
+    })
+}
+
+// Parse bitcoin amount from config bounce fee
+fn config_bounce_fee(bounce_fee: &Option<String>) -> Amount {
+    let config = bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE);
+    TalerAmount::from_str(&config)
+        .map_err(|s| s.to_string())
+        .and_then(|a| taler_to_btc(&a))
+        .or_fail(|a| {
+            format!(
+                "config value BOUNCE_FEE={} is not a valid bitcoin amount: {}",
+                config, a
+            )
+        })
+}
+
+// Check network match config currency
+fn check_network_currency(network: Network, currency: &str) {
+    match network {
+        Network::Bitcoin | Network::Regtest => {
+            if currency != "BTC" {
+                fail(format_args!(
+                    "wrong config CURRENCY = {} expected {}",
+                    currency, "BTC"
+                ))
+            }
         }
+        Network::Testnet | Network::Signet => unimplemented!(),
     }
 }
diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs
index 0e6b303..8d21beb 100644
--- a/btc-wire/src/loops/worker.rs
+++ b/btc-wire/src/loops/worker.rs
@@ -47,7 +47,7 @@ use crate::{
 use super::{LoopError, LoopResult};
 
 pub fn worker(mut rpc: AutoRpcWallet, mut db: AutoReconnectDb, state: 
&WireState) {
-    let mut lifetime = state.config.wire_lifetime;
+    let mut lifetime = state.lifetime;
     let mut status = true;
     let mut skip_notification = false;
 
@@ -432,7 +432,7 @@ fn sync_chain_withdraw(
             let date = SystemTime::UNIX_EPOCH + Duration::from_secs(full.time);
             let nb = db.execute(
                     "INSERT INTO tx_out (_date, amount, wtid, debit_acc, 
credit_acc, exchange_url, status, txid, request_uid) VALUES ($1, $2, $3, $4, 
$5, $6, $7, $8, $9) ON CONFLICT (wtid) DO NOTHING",
-                    &[&date, &amount.to_string(), &wtid.as_ref(), 
&btc_payto_url(&debit_addr).as_ref(), &btc_payto_url(credit_addr).as_ref(), 
&state.config.base_url.as_ref(), &(WithdrawStatus::Sent as i16), &id.as_ref(), 
&None::<&[u8]>],
+                    &[&date, &amount.to_string(), &wtid.as_ref(), 
&btc_payto_url(&debit_addr).as_ref(), &btc_payto_url(credit_addr).as_ref(), 
&state.base_url.as_ref(), &(WithdrawStatus::Sent as i16), &id.as_ref(), 
&None::<&[u8]>],
                         )?;
             if nb > 0 {
                 warn!(
@@ -446,7 +446,7 @@ fn sync_chain_withdraw(
         }
 
         // Check if stuck
-        if let Some(delay) = state.config.bump_delay {
+        if let Some(delay) = state.bump_delay {
             if confirmations == 0 && full.replaced_by_txid.is_none() {
                 let now = SystemTime::now()
                     .duration_since(SystemTime::UNIX_EPOCH)
diff --git a/btc-wire/src/main.rs b/btc-wire/src/main.rs
index 742f9a3..2d8b1d0 100644
--- a/btc-wire/src/main.rs
+++ b/btc-wire/src/main.rs
@@ -16,17 +16,13 @@
 use bitcoin::Network;
 use btc_wire::{
     config::{BitcoinConfig, WIRE_WALLET_NAME},
+    load_taler_config,
     rpc::{self, auto_rpc_common, auto_rpc_wallet, ErrorCode, Rpc},
-    rpc_utils::default_data_dir,
     WireState,
 };
 use clap::StructOpt;
 use common::{
-    config::{load_btc_config, Config, CoreConfig},
-    log::log::info,
-    named_spawn, password,
-    postgres::NoTls,
-    reconnect::auto_reconnect_db,
+    log::log::info, named_spawn, password, postgres::NoTls, 
reconnect::auto_reconnect_db,
 };
 use std::path::PathBuf;
 
@@ -68,14 +64,15 @@ fn main() {
 
 fn init(config: Option<PathBuf>, init: Init) {
     // Parse taler config
-    let config = CoreConfig::load_taler_config(config.as_deref(), Some("BTC"));
+    let taler_config = load_taler_config(config.as_deref());
+
     // Connect to database
-    let mut db = config
+    let mut db = taler_config
         .db_config
         .connect(NoTls)
         .expect("Failed to connect to database");
     // Parse bitcoin config
-    let btc_conf = 
BitcoinConfig::load(config.data_dir.unwrap_or_else(default_data_dir))
+    let btc_conf = BitcoinConfig::load(taler_config.custom, 
&taler_config.currency)
         .expect("Failed to load bitcoin configuration");
     // Connect to bitcoin node
     let mut rpc = Rpc::common(&btc_conf).expect("Failed to connect to bitcoin 
RPC server");
@@ -148,8 +145,8 @@ fn init(config: Option<PathBuf>, init: Init) {
 }
 
 fn run(config: Option<PathBuf>) {
-    let config = load_btc_config(config.as_deref());
-    let state: &'static _ = 
Box::leak(Box::new(WireState::from_taler_config(config)));
+    let state = WireState::load_taler_config(config.as_deref());
+    let state: &'static _ = Box::leak(Box::new(state));
 
     #[cfg(feature = "fail")]
     if state.btc_config.network == Network::Regtest {
@@ -170,9 +167,9 @@ fn run(config: Option<PathBuf>) {
     let rpc_analysis = auto_rpc_common(state.btc_config.clone());
     let rpc_worker = auto_rpc_wallet(state.btc_config.clone(), 
WIRE_WALLET_NAME);
 
-    let db_watcher = auto_reconnect_db(state.config.core.db_config.clone());
-    let db_analysis = auto_reconnect_db(state.config.core.db_config.clone());
-    let db_worker = auto_reconnect_db(state.config.core.db_config.clone());
+    let db_watcher = auto_reconnect_db(state.db_config.clone());
+    let db_analysis = auto_reconnect_db(state.db_config.clone());
+    let db_worker = auto_reconnect_db(state.db_config.clone());
     named_spawn("watcher", move || watcher(rpc_watcher, db_watcher));
     named_spawn("analysis", move || {
         analysis(rpc_analysis, db_analysis, state)
diff --git a/btc-wire/src/rpc.rs b/btc-wire/src/rpc.rs
index 195989a..073e979 100644
--- a/btc-wire/src/rpc.rs
+++ b/btc-wire/src/rpc.rs
@@ -141,10 +141,7 @@ impl Rpc {
             String::from("/")
         };
         let token = match &config.auth {
-            BtcAuth::Cookie => {
-                let cookie_path = config.dir.join(&config.cookie_path);
-                std::fs::read(cookie_path)?
-            }
+            BtcAuth::Cookie(path) => std::fs::read(path)?,
             BtcAuth::Auth(s) => s.as_bytes().to_vec(),
         };
         // Open connection
diff --git a/btc-wire/src/rpc_utils.rs b/btc-wire/src/rpc_utils.rs
index aefbb14..21767d8 100644
--- a/btc-wire/src/rpc_utils.rs
+++ b/btc-wire/src/rpc_utils.rs
@@ -15,12 +15,29 @@
 */
 use std::{path::PathBuf, str::FromStr};
 
-use bitcoin::{Address, Amount};
+use bitcoin::{Address, Amount, Network};
 
 use crate::rpc::{self, Rpc, Transaction};
 
-pub const CLIENT: &str = "client";
-pub const WIRE: &str = "wire";
+/// Default chain dir 
<https://github.com/bitcoin/bitcoin/blob/master/doc/files.md#data-directory-location>
+pub fn chain_dir(network: Network) -> &'static str {
+    match network {
+        Network::Bitcoin => "main",
+        Network::Testnet => "testnet3",
+        Network::Regtest => "regtest",
+        Network::Signet => "signet",
+    }
+}
+
+/// Default rpc port 
<https://github.com/bitcoin/bitcoin/blob/master/share/examples/bitcoin.conf>
+pub fn rpc_port(network: Network) -> u16 {
+    match network {
+        Network::Bitcoin => 8332,
+        Network::Testnet => 18332,
+        Network::Regtest => 18443,
+        Network::Signet => 38333,
+    }
+}
 
 /// Default bitcoin data_dir 
<https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md>
 pub fn default_data_dir() -> PathBuf {
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 220277e..a0d8172 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -11,9 +11,9 @@ rust-version = "1.56.1"
 # Serialization framework
 serde = { version = "1.0.136", features = ["derive"] }
 # Serialization helper
-serde_with = "1.11.0"
+serde_with = "1.12.0"
 # JSON serialization
-serde_json = "1.0.78"
+serde_json = "1.0.79"
 # Url format
 url = { version = "2.2.2", features = ["serde"] }
 # Crockford’s base32
@@ -21,17 +21,18 @@ base32 = "0.4.0"
 # Error macros
 thiserror = "1.0.30"
 # Ini files
-rust-ini = "0.17.0"
+rust-ini = "0.18.0"
 # Logging
 log = "0.4.14"
 flexi_logger = { version = "0.22.3", default-features = false, features = [
     "use_chrono_for_offset", # Temporary hack for multithreaded code 
https://rustsec.org/advisories/RUSTSEC-2020-0159
 ] }
-# Local timz
+# Localized time
 time = { version = "0.3.7", features = ["formatting", "macros"] }
 # Postgres client
 postgres = "0.19.2"
 # Secure random
-rand = { version = "0.8.4", features = ["getrandom"] }
+rand = { version = "0.8.5", features = ["getrandom"] }
 # Securely zero memory
-zeroize = "1.5.2"
+zeroize = "1.5.3"
+
diff --git a/common/src/config.rs b/common/src/config.rs
index 8edcb15..fec35e4 100644
--- a/common/src/config.rs
+++ b/common/src/config.rs
@@ -22,10 +22,37 @@ use std::{
 use url::Url;
 
 use crate::log::{fail, OrFail};
+pub use ini;
 
-pub trait Config: Sized {
-    /// Load using taler-config
-    fn load_taler_config(file: Option<&Path>, currency: Option<&'static str>) 
-> Self {
+// Depolymerizer taler config
+pub struct TalerConfig<T> {
+    // common
+    pub db_config: postgres::Config,
+    pub currency: String,
+    pub base_url: Url,
+    // wire-gateway
+    pub http_lifetime: Option<u32>,
+    pub port: u16,
+    pub unix_path: Option<PathBuf>,
+    // wire common
+    pub confirmation: Option<u16>,
+    pub bounce_fee: Option<String>,
+    pub wire_lifetime: Option<u32>,
+    pub bump_delay: Option<u32>,
+    pub payto: Option<Url>,
+    // custom config
+    pub custom: T,
+}
+
+impl TalerConfig<()> {
+    pub fn load(file: Option<&Path>) -> Self {
+        Self::load_with_custom(file, |_| {})
+    }
+}
+
+impl<T> TalerConfig<T> {
+    pub fn load_with_custom(file: Option<&Path>, lambda: fn(&Properties) -> T) 
-> Self {
+        // Load config using taler-config
         let mut cmd = Command::new("taler-config");
         cmd.arg("-d");
         if let Some(path) = file {
@@ -41,88 +68,22 @@ pub trait Config: Sized {
                 String::from_utf8_lossy(&output.stderr)
             );
         }
+        // Parse ini config
         let conf = 
ini::Ini::load_from_str(&String::from_utf8_lossy(&output.stdout))
             .expect("Failed to parse config");
         let taler = section(&conf, "taler");
-        let curr = require(taler, "CURRENCY", string);
-        if let Some(currency) = currency {
-            if currency != curr {
-                fail(format_args!(
-                    "expected config CURRENCY = {} got {}",
-                    currency, curr
-                ))
-            }
-        }
-        let section_name = match curr.as_str() {
+        let currency = required(taler, "CURRENCY", string);
+        let section_name = match currency.as_str() {
             "BTC" => "depolymerizer-bitcoin",
             "ETH" => "depolymerizer-ethereum",
             currency => fail(format_args!("Unsupported currency {}", 
currency)),
         };
 
         let dep = section(&conf, section_name);
-        return Self::load_from_ini(&conf, &curr, dep);
-    }
-    /// Load from loaded ini file
-    fn load_from_ini(ini: &Ini, currency: &str, dep: &Properties) -> Self;
-}
-
-#[derive(Debug, Clone)]
-pub struct CoreConfig {
-    pub db_config: postgres::Config,
-    pub data_dir: Option<PathBuf>,
-    pub currency: String,
-}
-
-impl Config for CoreConfig {
-    fn load_from_ini(_: &Ini, currency: &str, dep: &Properties) -> Self {
         Self {
-            db_config: require(dep, "DB_URL", postgres),
-            data_dir: path(dep, "DATA_DIR"),
+            db_config: required(dep, "DB_URL", postgres),
             currency: currency.to_string(),
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct GatewayConfig {
-    pub http_lifetime: Option<u32>,
-    pub port: u16,
-    pub unix_path: Option<PathBuf>,
-    pub payto: Url,
-    pub core: CoreConfig,
-}
-
-impl Config for GatewayConfig {
-    fn load_from_ini(ini: &Ini, currency: &str, dep: &Properties) -> Self {
-        Self {
-            port: nb(dep, "PORT").unwrap_or(8080),
-            unix_path: path(dep, "UNIXPATH"),
-            payto: require(dep, "PAYTO", url),
-            http_lifetime: nb(dep, "HTTP_LIFETIME")
-                .and_then(|nb| (nb != 0).then(|| Some(nb)))
-                .unwrap_or(None),
-            core: CoreConfig::load_from_ini(ini, currency, dep),
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub struct WireConfig {
-    pub base_url: Url,
-    pub confirmation: Option<u16>,
-    pub bounce_fee: Option<String>,
-    pub wire_lifetime: Option<u32>,
-    pub bump_delay: Option<u32>,
-    pub payto: Url,
-    pub core: CoreConfig,
-}
-
-impl Config for WireConfig {
-    fn load_from_ini(ini: &Ini, currency: &str, dep: &Properties) -> Self {
-        let ex = section(ini, "exchange");
-        Self {
-            base_url: require(ex, "BASE_URL", url),
-            payto: require(dep, "PAYTO", url),
+            base_url: required(section(&conf, "exchange"), "BASE_URL", url),
             confirmation: nb(dep, "CONFIRMATION"),
             bounce_fee: string(dep, "BOUNCE_FEE"),
             wire_lifetime: nb(dep, "WIRE_LIFETIME")
@@ -131,65 +92,65 @@ impl Config for WireConfig {
             bump_delay: nb(dep, "BUMP_DELAY")
                 .and_then(|nb| (nb != 0).then(|| Some(nb)))
                 .unwrap_or(None),
-            core: CoreConfig::load_from_ini(ini, currency, dep),
+            port: nb(dep, "PORT").unwrap_or(8080),
+            unix_path: path(dep, "UNIXPATH"),
+            payto: url(dep, "PAYTO"),
+            http_lifetime: nb(dep, "HTTP_LIFETIME")
+                .and_then(|nb| (nb != 0).then(|| Some(nb)))
+                .unwrap_or(None),
+            custom: lambda(dep),
         }
     }
-}
 
-pub type BtcConfig = WireConfig;
-
-pub fn load_btc_config(path: Option<&Path>) -> BtcConfig {
-    WireConfig::load_taler_config(path, Some("BTC"))
-}
-
-pub type EthConfig = WireConfig;
-
-pub fn load_eth_config(path: Option<&Path>) -> EthConfig {
-    WireConfig::load_taler_config(path, Some("ETH"))
+    // Enforce payto requirement
+    pub fn require_payto(&self) -> Url {
+        expect_config(self.payto.clone(), "PAYTO")
+    }
 }
 
 /* ----- Helper parsing functions ----- */
 
-fn section<'a>(ini: &'a Ini, name: &str) -> &'a Properties {
+pub fn section<'a>(ini: &'a Ini, name: &str) -> &'a Properties {
     ini.section(Some(name))
         .or_fail(|_| format!("missing config section {}", name))
 }
 
-fn require<T>(
+pub fn required<T>(
     properties: &Properties,
     name: &str,
     lambda: fn(properties: &Properties, name: &str) -> Option<T>,
 ) -> T {
-    let result = lambda(properties, name);
-    result.or_fail(|_| format!("missing config value {}", name))
+    expect_config(lambda(properties, name), name)
+}
+
+pub fn expect_config<T>(value: Option<T>, name: &str) -> T {
+    value.or_fail(|_| format!("missing config value {}", name))
 }
 
-fn string(properties: &Properties, name: &str) -> Option<String> {
+pub fn string(properties: &Properties, name: &str) -> Option<String> {
     properties.get(name).map(|s| s.to_string())
 }
 
-fn path(properties: &Properties, name: &str) -> Option<PathBuf> {
+pub fn path(properties: &Properties, name: &str) -> Option<PathBuf> {
     properties.get(name).map(|s| {
-        PathBuf::from_str(s)
-            .or_fail(|_| format!("config value {}={} is not a valid path", 
name, s))
+        PathBuf::from_str(s).or_fail(|_| format!("config value {}={} is not a 
valid path", name, s))
     })
 }
 
-fn nb<T: FromStr>(properties: &Properties, name: &str) -> Option<T> {
+pub fn nb<T: FromStr>(properties: &Properties, name: &str) -> Option<T> {
     properties.get(name).map(|s| {
         s.parse()
             .or_fail(|_| format!("config value {}={} is not a number", name, 
s))
     })
 }
 
-fn url(properties: &Properties, name: &str) -> Option<Url> {
+pub fn url(properties: &Properties, name: &str) -> Option<Url> {
     properties.get(name).map(|s| {
-        Url::parse(s)
-            .or_fail(|e| format!("config value {}={} is not a valid url: {}", 
name, s, e))
+        Url::parse(s).or_fail(|e| format!("config value {}={} is not a valid 
url: {}", name, s, e))
     })
 }
 
-fn postgres(properties: &Properties, name: &str) -> Option<postgres::Config> {
+pub fn postgres(properties: &Properties, name: &str) -> 
Option<postgres::Config> {
     properties.get(name).map(|s| {
         postgres::Config::from_str(s).or_fail(|e| {
             format!(
diff --git a/docs/taler-btc.conf b/docs/taler-btc.conf
new file mode 100644
index 0000000..cf0e1dd
--- /dev/null
+++ b/docs/taler-btc.conf
@@ -0,0 +1,17 @@
+# Full btc-wire configuration
+[taler]
+CURRENCY      = BTC
+
+[exchange]
+BASE_URL      = http://test.com
+
+[depolymerizer-bitcoin]
+DB_URL        = postgres://%2Fvar%2Frun%2Fpostgresql/btc-wire
+PAYTO         = payto://bitcoin/bc1qcr40fzphnh4mcwlv65kvdam4dxq977t2rn54qx
+PORT          = 8080
+CONF_PATH     = ~/.bitcoin
+CONFIRMATION  = 6
+BOUNCE_FEE    = BTC:0.00001
+HTTP_LIFETIME = 0
+WIRE_LIFETIME = 0
+BUMP_DELAY    = 0
diff --git a/docs/taler-eth.conf b/docs/taler-eth.conf
new file mode 100644
index 0000000..3e4243b
--- /dev/null
+++ b/docs/taler-eth.conf
@@ -0,0 +1,17 @@
+# Full eth-wire configuration
+[taler]
+CURRENCY      = ETH
+
+[exchange]
+BASE_URL      = http://test.com
+
+[depolymerizer-ethereum]
+DB_URL        = postgres://%2Fvar%2Frun%2Fpostgresql/eth-wire
+PAYTO         = payto://ethereum/425870d7b77ad5665ca982ff85c398222a70fe7c
+PORT          = 8080
+IPC_PATH      = ~/.ethereum/geth/geth.ipc
+CONFIRMATION  = 24
+BOUNCE_FEE    = ETH:0.00001
+HTTP_LIFETIME = 0
+WIRE_LIFETIME = 0
+BUMP_DELAY    = 0
diff --git a/eth-wire/Cargo.toml b/eth-wire/Cargo.toml
index ef4048a..03551df 100644
--- a/eth-wire/Cargo.toml
+++ b/eth-wire/Cargo.toml
@@ -11,14 +11,14 @@ fail = []
 
 [dependencies]
 # Cli args
-clap = { version = "3.1.1", features = ["derive"] }
+clap = { version = "3.1.5", features = ["derive"] }
 # Serialization library
 serde = { version = "1.0.136", features = ["derive"] }
-serde_json = "1.0.78"
+serde_json = "1.0.79"
 serde_repr = "0.1.7"
 hex = "0.4.3"
 # Ethereum serializable types
-ethereum-types = { version = "0.13.0", default-features = false, features = [
+ethereum-types = { version = "0.13.1", default-features = false, features = [
     "serialize",
 ] }
 # Error macros
diff --git a/eth-wire/README.md b/eth-wire/README.md
index 7e1f6ec..e15a062 100644
--- a/eth-wire/README.md
+++ b/eth-wire/README.md
@@ -1,38 +1,12 @@
 # eth-wire
 
-eth-wire is taler wire adapter for [go-ethereum](https://geth.ethereum.org/) 
node
+eth-wire is taler wire adapter for [go-ethereum](https://geth.ethereum.org/)
+node
 
-## Geth compatibility
+## Deposit metadata format
 
-Geth version 1.10.* is required
-
-## Install 
-
-`cargo install --path eth-wire`
-
-## Configuration
-
-### taler.conf
-
-The configuration is based on 
[taler.conf](https://docs.taler.net/manpages/taler.conf.5.html)
-
-``` ini
-# taler.conf - eth-wire default config
-[depolymerizer-ethereum]
-DATA_DIR     =
-CONFIRMATION = 24
-BOUNCE_FEE   = ETH:0.00001
-```
-
-## Getting Started
-
-1. Write configuration files
-2. Start geth
-3. Start PostgreSQL
-4. Initialize database `eth-wire initdb`
-5. Initialize wallet `eth-wire initwallet`
-6. Update configuration files with wallet info
-7. Run wire-gateway `wire-gateway`
-8. Run eth-wire `eth-wire`
+TODO
 
 ## Implementation details
+
+TODO
\ No newline at end of file
diff --git a/eth-wire/src/bin/eth-wire-utils.rs 
b/eth-wire/src/bin/eth-wire-utils.rs
index f4432ca..b640a0d 100644
--- a/eth-wire/src/bin/eth-wire-utils.rs
+++ b/eth-wire/src/bin/eth-wire-utils.rs
@@ -14,25 +14,19 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 use std::{
-    path::{Path, PathBuf},
+    path::PathBuf,
     process::exit,
     str::FromStr,
     time::{Duration, Instant},
 };
 
 use clap::StructOpt;
-use common::{
-    api_common::Amount,
-    config::{Config, CoreConfig},
-    log::init,
-    password,
-    postgres::NoTls,
-    rand_slice,
-};
+use common::{api_common::Amount, log::init, password, postgres::NoTls, 
rand_slice};
 use eth_wire::{
-    rpc::{hex::Hex, Rpc, TransactionRequest, RpcClient},
+    load_taler_config,
+    rpc::{hex::Hex, Rpc, RpcClient, TransactionRequest},
     taler_util::{taler_to_eth, TRUNC},
-    SyncState, RpcExtended,
+    RpcExtended, SyncState,
 };
 use ethereum_types::{H160, U256};
 
@@ -110,14 +104,10 @@ enum Cmd {
 fn main() {
     init();
     let args: Args = Args::parse();
-    let config = args
-        .config
-        .map(|path| CoreConfig::load_taler_config(Some(&path), Some("ETH")));
-    let data_dir: Option<&Path> = config
-        .as_ref()
-        .and_then(|it| it.data_dir.as_deref())
-        .or(args.datadir.as_deref());
-    let mut rpc = 
Rpc::new(data_dir.unwrap_or(&PathBuf::from("/tmp/")).join("geth.ipc")).unwrap();
+    let taler_config = load_taler_config(args.config.as_deref());
+
+    let ipc_path = args.datadir.unwrap_or(taler_config.custom);
+    let mut rpc = Rpc::new(ipc_path).unwrap();
     let passwd = password();
     match args.cmd {
         Cmd::Deposit(TransactionCmd {
@@ -175,7 +165,7 @@ fn main() {
         }
         Cmd::Resetdb => {
             let block = rpc.earliest_block().unwrap();
-            let mut db = config.unwrap().db_config.connect(NoTls).unwrap();
+            let mut db = taler_config.db_config.connect(NoTls).unwrap();
             let mut tx = db.transaction().unwrap();
             // Clear transaction tables and reset state
             tx.execute("DELETE FROM tx_in", &[]).unwrap();
@@ -225,7 +215,7 @@ fn main() {
             }
         }
         Cmd::Connect { datadir } => {
-            let mut peer = Rpc::new(datadir.join("geth.ipc")).unwrap();
+            let mut peer = Rpc::new(datadir).unwrap();
             let mut enode = peer.node_info().unwrap().enode;
             // Replace ip with localhost because it is broken
             enode.set_host(Some("127.0.0.1")).unwrap();
@@ -239,7 +229,7 @@ fn main() {
             }
         }
         Cmd::Disconnect { datadir } => {
-            let mut peer = Rpc::new(datadir.join("geth.ipc")).unwrap();
+            let mut peer = Rpc::new(datadir).unwrap();
             let mut enode = peer.node_info().unwrap().enode;
             // Replace ip with localhost because it is broken
             enode.set_host(Some("127.0.0.1")).unwrap();
diff --git a/eth-wire/src/lib.rs b/eth-wire/src/lib.rs
index 0660b64..9a13378 100644
--- a/eth-wire/src/lib.rs
+++ b/eth-wire/src/lib.rs
@@ -14,17 +14,24 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 
-use std::{fmt::Debug, str::FromStr, sync::atomic::AtomicU32};
+use std::{
+    fmt::Debug,
+    path::{Path, PathBuf},
+    str::FromStr,
+    sync::atomic::AtomicU32,
+};
 
-use common::{api_common::Amount, config::EthConfig, url::Url};
+use common::{api_common::Amount, config::TalerConfig, log::OrFail, postgres, 
url::Url};
 use ethereum_types::{Address, H160, H256, U256, U64};
 use metadata::{InMetadata, OutMetadata};
 use rpc::{hex::Hex, Rpc, RpcClient, RpcStream, Transaction};
+use rpc_utils::default_data_dir;
 use serde::de::DeserializeOwned;
 use taler_util::{eth_payto_addr, taler_to_eth};
 
 pub mod metadata;
 pub mod rpc;
+mod rpc_utils;
 pub mod taler_util;
 
 pub trait RpcExtended: RpcClient {
@@ -202,33 +209,59 @@ impl SyncState {
 
 const DEFAULT_CONFIRMATION: u16 = 24;
 const DEFAULT_BOUNCE_FEE: &str = "ETH:0.00001";
+
 pub struct WireState {
     pub confirmation: AtomicU32,
     pub max_confirmations: u32,
     pub address: H160,
-    pub config: EthConfig,
     pub bounce_fee: U256,
+    pub ipc_path: PathBuf,
+    pub lifetime: Option<u32>,
+    pub bump_delay: Option<u32>,
+    pub base_url: Url,
+    pub payto: Url,
+    pub db_config: postgres::Config,
 }
 
 impl WireState {
-    pub fn from_taler_config(config: EthConfig) -> Self {
-        let init_confirmation = 
config.confirmation.unwrap_or(DEFAULT_CONFIRMATION) as u32;
+    pub fn load_taler_config(file: Option<&Path>) -> Self {
+        let taler_config = load_taler_config(file);
+        let init_confirmation = 
taler_config.confirmation.unwrap_or(DEFAULT_CONFIRMATION) as u32;
+        let payto = taler_config.require_payto();
         Self {
             confirmation: AtomicU32::new(init_confirmation),
             max_confirmations: init_confirmation * 2,
-            address: eth_payto_addr(&config.payto).unwrap(),
-            bounce_fee: config_bounce_fee(&config),
-            config,
+            address: eth_payto_addr(&payto).unwrap(),
+            ipc_path: taler_config.custom,
+            bounce_fee: config_bounce_fee(&taler_config.bounce_fee),
+            lifetime: taler_config.wire_lifetime,
+            bump_delay: taler_config.bump_delay,
+            base_url: taler_config.base_url,
+            db_config: taler_config.db_config,
+            payto,
         }
     }
 }
 
-fn config_bounce_fee(config: &EthConfig) -> U256 {
-    let config = config.bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE);
+// Load taler config with eth-wire specific config
+pub fn load_taler_config(file: Option<&Path>) -> TalerConfig<PathBuf> {
+    TalerConfig::load_with_custom(file, |dep| {
+        common::config::path(dep, "IPC_PATH").unwrap_or_else(default_data_dir)
+    })
+}
+
+// Parse ethereum value from config bounce fee
+fn config_bounce_fee(bounce_fee: &Option<String>) -> U256 {
+    let config = bounce_fee.as_deref().unwrap_or(DEFAULT_BOUNCE_FEE);
     Amount::from_str(config)
-        .ok()
-        .and_then(|a| taler_to_eth(&a).ok())
-        .expect("config value BOUNCE_FEE is no a valid ethereum amount")
+        .map_err(|s| s.to_string())
+        .and_then(|a| taler_to_eth(&a))
+        .or_fail(|a| {
+            format!(
+                "config value BOUNCE_FEE={} is not a valid ethereum amount: 
{}",
+                config, a
+            )
+        })
 }
 
 #[cfg(test)]
diff --git a/eth-wire/src/loops/worker.rs b/eth-wire/src/loops/worker.rs
index 67b3d0c..d2fd409 100644
--- a/eth-wire/src/loops/worker.rs
+++ b/eth-wire/src/loops/worker.rs
@@ -41,7 +41,7 @@ use crate::{
 use super::LoopResult;
 
 pub fn worker(mut rpc: AutoRpcWallet, mut db: AutoReconnectDb, state: 
&WireState) {
-    let mut lifetime = state.config.wire_lifetime;
+    let mut lifetime = state.lifetime;
     let mut status = true;
     let mut skip_notification = false;
 
@@ -276,7 +276,7 @@ fn sync_chain_incoming_confirmed(
                 let amount = eth_to_taler(&tx.value);
                 let credit_addr = tx.from.expect("Not coinbase");
                 let nb = db.execute("INSERT INTO tx_in (_date, amount, 
reserve_pub, debit_acc, credit_acc) VALUES ($1, $2, $3, $4, $5) ON CONFLICT 
(reserve_pub) DO NOTHING ", &[
-                &date, &amount.to_string(), &reserve_pub.as_ref(), 
&eth_payto_url(&credit_addr).as_ref(), &state.config.payto.as_ref()
+                &date, &amount.to_string(), &reserve_pub.as_ref(), 
&eth_payto_url(&credit_addr).as_ref(), &state.payto.as_ref()
             ])?;
                 if nb > 0 {
                     info!(
@@ -351,7 +351,7 @@ fn sync_chain_outgoing(tx: &SyncTransaction, db: &mut 
Client, state: &WireState)
                     let date = SystemTime::now();
                     let nb = db.execute(
                     "INSERT INTO tx_out (_date, amount, wtid, debit_acc, 
credit_acc, exchange_url, status, txid, request_uid) VALUES ($1, $2, $3, $4, 
$5, $6, $7, $8, $9) ON CONFLICT (wtid) DO NOTHING",
-                    &[&date, &amount.to_string(), &wtid.as_ref(), 
&eth_payto_url(&state.address).as_ref(), &eth_payto_url(&credit_addr).as_ref(), 
&state.config.base_url.as_ref(), &(WithdrawStatus::Sent as i16), 
&tx.hash.as_ref(), &None::<&[u8]>],
+                    &[&date, &amount.to_string(), &wtid.as_ref(), 
&eth_payto_url(&state.address).as_ref(), &eth_payto_url(&credit_addr).as_ref(), 
&state.base_url.as_ref(), &(WithdrawStatus::Sent as i16), &tx.hash.as_ref(), 
&None::<&[u8]>],
                         )?;
                     if nb > 0 {
                         warn!(
@@ -446,7 +446,7 @@ fn withdraw(db: &mut Client, rpc: &mut Rpc, state: 
&WireState) -> LoopResult<boo
 
 /// Bump a stuck transaction, return false if no more stuck transactions are 
found
 fn bump(db: &mut Client, rpc: &mut Rpc, state: &WireState) -> LoopResult<bool> 
{
-    if let Some(delay) = state.config.bump_delay {
+    if let Some(delay) = state.bump_delay {
         // We rely on the advisory lock to ensure we are the only one sending 
transactions
         let row = db.query_opt(
         "SELECT id, txid FROM tx_out WHERE status=$1 AND EXTRACT(EPOCH FROM 
(now() - sent)) > $2 ORDER BY _date LIMIT 1",
diff --git a/eth-wire/src/main.rs b/eth-wire/src/main.rs
index fcb907b..4cf11ca 100644
--- a/eth-wire/src/main.rs
+++ b/eth-wire/src/main.rs
@@ -17,15 +17,10 @@
 use std::path::PathBuf;
 
 use clap::StructOpt;
-use common::{
-    config::{load_eth_config, Config, CoreConfig},
-    named_spawn, password,
-    postgres::NoTls,
-    reconnect::auto_reconnect_db,
-};
+use common::{named_spawn, password, postgres::NoTls, 
reconnect::auto_reconnect_db};
 use eth_wire::{
     rpc::{auto_rpc_common, auto_rpc_wallet, Rpc, RpcClient},
-    SyncState, WireState,
+    SyncState, WireState, load_taler_config,
 };
 use ethereum_types::H160;
 use loops::{analysis::analysis, watcher::watcher, worker::worker};
@@ -64,20 +59,14 @@ fn main() {
 
 fn init(config: Option<PathBuf>, init: Init) {
     // Parse taler config
-    let config = CoreConfig::load_taler_config(config.as_deref(), Some("ETH"));
+    let taler_config = load_taler_config(config.as_deref());
     // Connect to database
-    let mut db = config
+    let mut db = taler_config
         .db_config
         .connect(NoTls)
         .expect("Failed to connect to database");
     // Connect to ethereum node
-    let mut rpc = Rpc::new(
-        config
-            .data_dir
-            .unwrap_or(PathBuf::from("/tmp/"))
-            .join("geth.ipc"),
-    )
-    .expect("Failed to connect to ethereum RPC server");
+    let mut rpc = Rpc::new(taler_config.custom).expect("Failed to connect to 
ethereum RPC server");
 
     match init {
         Init::Initdb => {
@@ -156,38 +145,16 @@ fn init(config: Option<PathBuf>, init: Init) {
 }
 
 fn run(config: Option<PathBuf>) {
-    let config = load_eth_config(config.as_deref());
-    let state: &'static _ = 
Box::leak(Box::new(WireState::from_taler_config(config)));
-
-    let rpc_worker = auto_rpc_wallet(
-        state
-            .config
-            .core
-            .data_dir
-            .clone()
-            .unwrap_or(PathBuf::from("/tmp/")),
-        state.address,
-    );
-    let rpc_analysis = auto_rpc_common(
-        state
-            .config
-            .core
-            .data_dir
-            .clone()
-            .unwrap_or(PathBuf::from("/tmp/")),
-    );
-    let rpc_watcher = auto_rpc_common(
-        state
-            .config
-            .core
-            .data_dir
-            .clone()
-            .unwrap_or(PathBuf::from("/tmp/")),
-    );
-
-    let db_watcher = auto_reconnect_db(state.config.core.db_config.clone());
-    let db_analysis = auto_reconnect_db(state.config.core.db_config.clone());
-    let db_worker = auto_reconnect_db(state.config.core.db_config.clone());
+    let state = WireState::load_taler_config(config.as_deref());
+    let state: &'static _ = Box::leak(Box::new(state));
+
+    let rpc_worker = auto_rpc_wallet(state.ipc_path.clone(), state.address);
+    let rpc_analysis = auto_rpc_common(state.ipc_path.clone());
+    let rpc_watcher = auto_rpc_common(state.ipc_path.clone());
+
+    let db_watcher = auto_reconnect_db(state.db_config.clone());
+    let db_analysis = auto_reconnect_db(state.db_config.clone());
+    let db_worker = auto_reconnect_db(state.db_config.clone());
 
     named_spawn("watcher", move || watcher(rpc_watcher, db_watcher));
     named_spawn("analysis", move || {
diff --git a/eth-wire/src/rpc.rs b/eth-wire/src/rpc.rs
index 1d60b94..f94d286 100644
--- a/eth-wire/src/rpc.rs
+++ b/eth-wire/src/rpc.rs
@@ -34,9 +34,9 @@ use self::hex::Hex;
 
 pub type AutoRpcWallet = AutoReconnect<(PathBuf, Address), Rpc>;
 
-pub fn auto_rpc_wallet(data_dir: PathBuf, address: Address) -> AutoRpcWallet {
+pub fn auto_rpc_wallet(ipc_path: PathBuf, address: Address) -> AutoRpcWallet {
     AutoReconnect::new(
-        (data_dir.join("geth.ipc"), address),
+        (ipc_path, address),
         |(path, address)| {
             let mut rpc = Rpc::new(path)
                 .map_err(|err| error!("connect RPC: {}", err))
@@ -52,9 +52,9 @@ pub fn auto_rpc_wallet(data_dir: PathBuf, address: Address) 
-> AutoRpcWallet {
 
 pub type AutoRpcCommon = AutoReconnect<PathBuf, Rpc>;
 
-pub fn auto_rpc_common(data_dir: PathBuf) -> AutoRpcCommon {
+pub fn auto_rpc_common(ipc_path: PathBuf) -> AutoRpcCommon {
     AutoReconnect::new(
-        data_dir.join("geth.ipc"),
+        ipc_path,
         |path| {
             Rpc::new(path)
                 .map_err(|err| error!("connect RPC: {}", err))
@@ -111,7 +111,13 @@ pub struct Rpc {
 
 impl Rpc {
     pub fn new(path: impl AsRef<Path>) -> io::Result<Self> {
-        let conn = UnixStream::connect(&path)?;
+        let path = path.as_ref();
+
+        let conn = if path.is_dir() {
+            UnixStream::connect(path.join("geth.ipc"))
+        } else {
+            UnixStream::connect(path)
+        }?;
 
         Ok(Self {
             id: 0,
@@ -232,7 +238,7 @@ enum NotificationOrResponse<T, N> {
     Response(RpcResponse<T>),
 }
 
-/// A notification stream wrapping an rpc client 
+/// A notification stream wrapping an rpc client
 pub struct RpcStream<'a, N: Debug + DeserializeOwned> {
     rpc: &'a mut Rpc,
     id: String,
diff --git a/eth-wire/src/rpc_utils.rs b/eth-wire/src/rpc_utils.rs
new file mode 100644
index 0000000..ccfa00d
--- /dev/null
+++ b/eth-wire/src/rpc_utils.rs
@@ -0,0 +1,20 @@
+use std::{path::PathBuf, str::FromStr};
+
+/// Default geth data_dir 
<https://geth.ethereum.org/docs/install-and-build/backup-restore#data-directory>
+pub fn default_data_dir() -> PathBuf {
+    if cfg!(target_os = "windows") {
+        PathBuf::from_str(&std::env::var("APPDATA").unwrap())
+            .unwrap()
+            .join("Ethereum")
+    } else if cfg!(target_os = "linux") {
+        PathBuf::from_str(&std::env::var("HOME").unwrap())
+            .unwrap()
+            .join(".ethereum")
+    } else if cfg!(target_os = "macos") {
+        PathBuf::from_str(&std::env::var("HOME").unwrap())
+            .unwrap()
+            .join("Library/Ethereum")
+    } else {
+        unimplemented!("Only windows, linux or macos")
+    }
+}
diff --git a/instrumentation/Cargo.toml b/instrumentation/Cargo.toml
index 76365a8..3172f14 100644
--- a/instrumentation/Cargo.toml
+++ b/instrumentation/Cargo.toml
@@ -7,14 +7,17 @@ rust-version = "1.56.1"
 
 [dependencies]
 # Cli args parser
-clap = { version = "3.1.1", features = ["derive"] }
+clap = { version = "3.1.5", features = ["derive"] }
 common = { path = "../common" }
 # Bitcoin
 btc-wire = { path = "../btc-wire" }
 bitcoin = { version = "0.27.1", default-features = false }
 # Ethereum
 eth-wire = { path = "../eth-wire" }
-ethereum-types = { version = "0.13.0", default-features = false }
+ethereum-types = { version = "0.13.1", default-features = false }
 hex = "0.4.3"
 # Wire Gateway
 ureq = { version = "2.4.0", features = ["json"] }
+
+[build-dependencies]
+clap_mangen = "0.1"
diff --git a/instrumentation/src/btc.rs b/instrumentation/src/btc.rs
index 396c700..a0096bb 100644
--- a/instrumentation/src/btc.rs
+++ b/instrumentation/src/btc.rs
@@ -24,7 +24,7 @@ use btc_wire::{
     taler_utils::{btc_payto_url, btc_to_taler},
     WireState,
 };
-use common::{config::load_btc_config, rand_slice};
+use common::rand_slice;
 
 use crate::{check_incoming, check_outgoing, print_now, transfer};
 
@@ -59,8 +59,7 @@ fn wait_for_pending(since: &mut BlockHash, client_rpc: &mut 
Rpc, wire_rpc: &mut
 }
 
 pub fn btc_test(config: Option<&Path>, base_url: &str) {
-    let config = load_btc_config(config);
-    let state = WireState::from_taler_config(config);
+    let state = WireState::load_taler_config(config);
 
     if state.btc_config.network == Network::Bitcoin {
         panic!("You should never run this test on a real bitcoin network");
@@ -189,7 +188,7 @@ pub fn btc_test(config: Option<&Path>, base_url: &str) {
     transfer(
         base_url,
         &wtid,
-        &state.config.base_url,
+        &state.base_url,
         btc_payto_url(&client_addr),
         &taler_test_amount,
     );
@@ -199,5 +198,5 @@ pub fn btc_test(config: Option<&Path>, base_url: &str) {
     let last_client_balance = client_rpc.get_balance().unwrap();
     assert_eq!(new_client_balance + test_amount, last_client_balance);
 
-    check_outgoing(base_url, &wtid, &state.config.base_url, 
&taler_test_amount);
+    check_outgoing(base_url, &wtid, &state.base_url, &taler_test_amount);
 }
diff --git a/instrumentation/src/eth.rs b/instrumentation/src/eth.rs
index 4c51898..8ac5187 100644
--- a/instrumentation/src/eth.rs
+++ b/instrumentation/src/eth.rs
@@ -1,9 +1,6 @@
-use std::{
-    path::{Path, PathBuf},
-    time::Duration,
-};
+use std::{path::Path, time::Duration};
 
-use common::{config::load_eth_config, rand_slice};
+use common::rand_slice;
 use eth_wire::{
     metadata::OutMetadata,
     rpc::{hex::Hex, Rpc, RpcClient, TransactionRequest},
@@ -27,22 +24,13 @@ fn wait_for_pending(rpc: &mut Rpc) {
 }
 
 pub fn eth_test(config: Option<&Path>, base_url: &str) {
-    let config = load_eth_config(config);
-    let state = WireState::from_taler_config(config);
+    let state = WireState::load_taler_config(config);
     // TODO eth network check
     let min_fund = U256::from(100_000 * TRUNC);
     let test_amount = U256::from(20_000 * TRUNC);
     let taler_test_amount = eth_to_taler(&test_amount);
 
-    let mut rpc = Rpc::new(
-        state
-            .config
-            .core
-            .data_dir
-            .unwrap_or_else(|| PathBuf::from("/tmp/"))
-            .join("geth.ipc"),
-    )
-    .unwrap();
+    let mut rpc = Rpc::new(state.ipc_path).unwrap();
 
     // Load client
     let client_addr = rpc
@@ -164,7 +152,7 @@ pub fn eth_test(config: Option<&Path>, base_url: &str) {
     transfer(
         base_url,
         &wtid,
-        &state.config.base_url,
+        &state.base_url,
         eth_payto_url(&client_addr),
         &taler_test_amount,
     );
@@ -174,5 +162,5 @@ pub fn eth_test(config: Option<&Path>, base_url: &str) {
     let last_client_balance = rpc.get_balance(&client_addr).unwrap();
     assert_eq!(new_client_balance + test_amount, last_client_balance);
 
-    check_outgoing(base_url, &wtid, &state.config.base_url, 
&taler_test_amount);
+    check_outgoing(base_url, &wtid, &state.base_url, &taler_test_amount);
 }
diff --git a/instrumentation/src/main.rs b/instrumentation/src/main.rs
index e6d45b2..a534d7c 100644
--- a/instrumentation/src/main.rs
+++ b/instrumentation/src/main.rs
@@ -21,7 +21,7 @@ use clap::StructOpt;
 use common::{
     api_common::{Amount, Base32},
     api_wire::{IncomingBankTransaction, IncomingHistory, OutgoingHistory, 
TransferRequest},
-    config::{Config, GatewayConfig},
+    config::TalerConfig,
     rand_slice,
     url::Url,
 };
@@ -92,10 +92,10 @@ struct Args {
 pub fn main() {
     common::log::init();
     let args = Args::parse();
-    let gateway_conf = 
GatewayConfig::load_taler_config(args.config.as_deref(), None);
-    let base_url = format!("http://localhost:{}";, gateway_conf.port);
+    let taler_config = TalerConfig::load(args.config.as_deref());
+    let base_url = format!("http://localhost:{}";, taler_config.port);
 
-    match gateway_conf.core.currency.as_str() {
+    match taler_config.currency.as_str() {
         "BTC" => btc_test(args.config.as_deref(), &base_url),
         "ETH" => eth_test(args.config.as_deref(), &base_url),
         _ => unimplemented!(),
diff --git a/test/btc/config.sh b/test/btc/config.sh
index 1be152b..f096e6a 100644
--- a/test/btc/config.sh
+++ b/test/btc/config.sh
@@ -20,8 +20,8 @@ function test() {
     cleanup
 }
 
-for config in bitcoin_auth.conf bitcoin_auth1.conf bitcoin_auth2.conf 
bitcoin_auth3.conf bitcoin_auth4.conf bitcoin_auth5.conf; do
-    test $config
+for n in `seq 0 5`; do
+    test "bitcoin_auth$n.conf"
 done
 
 echo "All tests passed!"
\ No newline at end of file
diff --git a/test/btc/wire.sh b/test/btc/wire.sh
index 08e4d8f..0cef4c6 100644
--- a/test/btc/wire.sh
+++ b/test/btc/wire.sh
@@ -44,7 +44,7 @@ for n in `$SEQ`; do
         -C payto://bitcoin/$CLIENT \
         -a BTC:0.0000$n > /dev/null
 done
-sleep 10
+sleep 15
 mine_btc # Mine transactions
 check_balance 9.95514310 ""
 echo " OK"
diff --git a/test/common.sh b/test/common.sh
index 71dcbcb..7c0a7b9 100644
--- a/test/common.sh
+++ b/test/common.sh
@@ -47,17 +47,18 @@ ETH_CLI2="geth -datadir=$WIRE_DIR2"
 # Load test.conf as bash variables
 function load_config() {
     cp ${BASH_SOURCE%/*}/conf/$CONFIG $CONF
-    echo -e "\nDATA_DIR = ${WIRE_DIR}" >> $CONF
+    echo -e "\nCONF_PATH = ${WIRE_DIR}" >> $CONF
+    echo -e "IPC_PATH = ${WIRE_DIR}" >> $CONF
     source <(grep = $CONF | sed 's/ *= */=/' | sed 's/=\(.*\)/="\1"/g1')
     BANK_ENDPOINT=http://127.0.0.1:$PORT/
     if [ "$CURRENCY" == "BTC" ]; then
         WIRE_CLI="btc-wire -c $CONF"
         WIRE_UTILS="btc-wire-utils -c $CONF"
-        WIRE_UTILS2="btc-wire-utils -d $WIRE_DIR2"
+        WIRE_UTILS2="btc-wire-utils -c $CONF -d $WIRE_DIR2"
     else
         WIRE_CLI="eth-wire -c $CONF"
         WIRE_UTILS="eth-wire-utils -c $CONF"
-        WIRE_UTILS2="eth-wire-utils -d $WIRE_DIR2"
+        WIRE_UTILS2="eth-wire-utils -c $CONF -d $WIRE_DIR2"
     fi
 }
 
diff --git a/test/conf/bitcoin_auth.conf b/test/conf/bitcoin_auth0.conf
similarity index 100%
rename from test/conf/bitcoin_auth.conf
rename to test/conf/bitcoin_auth0.conf
diff --git a/wire-gateway/Cargo.toml b/wire-gateway/Cargo.toml
index 2104ec4..4015280 100644
--- a/wire-gateway/Cargo.toml
+++ b/wire-gateway/Cargo.toml
@@ -7,17 +7,17 @@ rust-version = "1.56.1"
 
 [dependencies]
 # Http library
-hyper = { version = "0.14.16", features = ["http1", "server", "runtime"] }
+hyper = { version = "0.14.17", features = ["http1", "server", "runtime"] }
 # Hyper compat lib for unix domain socket
 hyperlocal = "0.8.0"
 # Async runtime
-tokio = { version = "1.16.1", features = ["net", "macros", "rt-multi-thread"] }
+tokio = { version = "1.17.0", features = ["net", "macros", "rt-multi-thread"] }
 # Serialization framework
 serde = { version = "1.0.136", features = ["derive"] }
 # Serialization helper
-serde_with = "1.11.0"
+serde_with = "1.12.0"
 # JSON serialization
-serde_json = "1.0.78"
+serde_json = "1.0.79"
 # Url query serialization
 serde_urlencoded = "0.7.1"
 # Error macros
@@ -34,9 +34,9 @@ common = { path = "../common" }
 # Bitcoin types
 bitcoin = { version = "0.27.1", optional = true }
 # Euthereum types
-ethereum-types = { version = "0.13.0", default-features = false, optional = 
true }
+ethereum-types = { version = "0.13.1", default-features = false, optional = 
true }
 # Cli args parser
-clap = { version = "3.1.1", features = ["derive"] }
+clap = { version = "3.1.5", features = ["derive"] }
 
 [features]
 default = ["btc", "eth"]
diff --git a/wire-gateway/src/main.rs b/wire-gateway/src/main.rs
index fbba4fb..f9c14b2 100644
--- a/wire-gateway/src/main.rs
+++ b/wire-gateway/src/main.rs
@@ -1,4 +1,3 @@
-use clap::StructOpt;
 /*
   This file is part of TALER
   Copyright (C) 2022 Taler Systems SA
@@ -14,16 +13,17 @@ use clap::StructOpt;
   You should have received a copy of the GNU Affero General Public License 
along with
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
+use clap::StructOpt;
 use common::{
     api_common::{ShortHashCode, Timestamp},
     api_wire::{
         HistoryParams, IncomingBankTransaction, IncomingHistory, 
OutgoingBankTransaction,
         OutgoingHistory, TransferRequest, TransferResponse,
     },
-    config::{Config, GatewayConfig},
+    config::TalerConfig,
     error_codes::ErrorCode,
     log::log::{error, info, log, Level},
-    postgres::fallible_iterator::FallibleIterator,
+    postgres::{self, fallible_iterator::FallibleIterator},
     sql::{sql_amount, sql_array, sql_safe_u64, sql_url},
     url::Url,
 };
@@ -51,7 +51,9 @@ mod json;
 
 struct ServerState {
     pool: Pool,
-    config: GatewayConfig,
+    db_config: postgres::Config,
+    payto: Url,
+    currency: String,
     payto_check: fn(&Url) -> bool,
     notify: Notify,
     lifetime: Option<AtomicU32>,
@@ -98,13 +100,13 @@ struct Args {
 async fn main() {
     common::log::init();
     let args = Args::parse();
-    let conf = GatewayConfig::load_taler_config(args.config.as_deref(), None);
+    let taler_config = TalerConfig::load(args.config.as_deref());
 
     #[cfg(feature = "test")]
     common::log::log::warn!("Running with test admin endpoint unsuitable for 
production");
 
     // Parse postgres url
-    let config = &conf.core.db_config;
+    let config = &taler_config.db_config;
     // TODO find a way to clean this ugly mess
     let mut cfg = deadpool_postgres::Config::new();
     cfg.user = config.get_user().map(|it| it.to_string());
@@ -129,19 +131,22 @@ async fn main() {
     cfg.connect_timeout = config.get_connect_timeout().cloned();
 
     let pool = cfg.create_pool(Some(Runtime::Tokio1), NoTls).unwrap();
+    let payto = taler_config.require_payto();
     let state = ServerState {
         pool,
-        payto_check: match conf.core.currency.as_str() {
+        payto_check: match taler_config.currency.as_str() {
             #[cfg(feature = "btc")]
             "BTC" => check_pay_to_btc,
             #[cfg(feature = "eth")]
             "ETH" => check_pay_to_eth,
             currency => unimplemented!("Unsupported currency {}", currency),
         },
-        config: conf.clone(),
         notify: Notify::new(),
-        lifetime: conf.http_lifetime.map(AtomicU32::new),
+        lifetime: taler_config.http_lifetime.map(AtomicU32::new),
         status: AtomicBool::new(true),
+        db_config: taler_config.db_config,
+        payto,
+        currency: taler_config.currency,
     };
     let state: &'static ServerState = Box::leak(Box::new(state));
     std::thread::spawn(move || status_watcher(state));
@@ -189,7 +194,7 @@ async fn main() {
         if let Err(e) = server.await {
             error!("server: {}", e);
         }
-    } else if let Some(path) = conf.unix_path {
+    } else if let Some(path) = taler_config.unix_path {
         use hyperlocal::UnixServerExt;
         info!("Server listening on unix domain socket {:?}", path);
         if let Err(err) = std::fs::remove_file(&path) {
@@ -205,7 +210,7 @@ async fn main() {
             error!("server: {}", e);
         }
     } else {
-        let addr = ([0, 0, 0, 0], state.config.port).into();
+        let addr = ([0, 0, 0, 0], taler_config.port).into();
         info!("Server listening on http://{}";, &addr);
         let server = Server::bind(&addr)
             .serve(make_service)
@@ -307,7 +312,7 @@ async fn router(
                     ErrorCode::GENERIC_PAYTO_URI_MALFORMED,
                 ));
             }
-            if request.amount.currency != state.config.core.currency {
+            if request.amount.currency != state.currency {
                 return Err(ServerError::code(
                     StatusCode::BAD_REQUEST,
                     ErrorCode::GENERIC_PARAMETER_MALFORMED,
@@ -348,7 +353,7 @@ async fn router(
             let timestamp = Timestamp::now();
             let tx = db.transaction().await?;
             let row = tx.query_one("INSERT INTO tx_out (amount, wtid, 
debit_acc, credit_acc, exchange_url, request_uid) VALUES ($1, $2, $3, $4, $5, 
$6) RETURNING id", &[
-                &request.amount.to_string(), &request.wtid.as_ref(), 
&state.config.payto.as_ref(),  &request.credit_account.as_ref(), 
&request.exchange_base_url.as_ref(), &request.request_uid.as_ref()
+                &request.amount.to_string(), &request.wtid.as_ref(), 
&state.payto.as_ref(),  &request.credit_account.as_ref(), 
&request.exchange_base_url.as_ref(), &request.request_uid.as_ref()
             ]).await?;
             tx.execute("NOTIFY new_tx", &[]).await?;
             tx.commit().await?;
@@ -480,7 +485,7 @@ async fn router(
 /// Listen to backend status change
 fn status_watcher(state: &'static ServerState) {
     fn inner(state: &'static ServerState) -> Result<(), Box<dyn 
std::error::Error>> {
-        let mut db = state.config.core.db_config.connect(NoTls)?;
+        let mut db = state.db_config.connect(NoTls)?;
         // Register as listener
         db.batch_execute("LISTEN status")?;
         loop {
@@ -497,7 +502,7 @@ fn status_watcher(state: &'static ServerState) {
     loop {
         if let Err(err) = inner(state) {
             error!("status-watcher: {}", err);
+            std::thread::sleep(Duration::from_secs(5));
         }
-        std::thread::sleep(Duration::from_secs(5));
     }
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]