Since we introduced our own parsing function for command line arguments, we have to make sure that clap's behaviour is handled correctly.
Clap's `get_matches_from_safe` returns an error of a certain kind, of which `ErrorKind::HelpDisplayed` and `ErrorKind::VersionDisplayed ` have to be handled to properly print the help/version and exit the program.
The clap error includes the message, so we print help/version in main now and ensure the program exits with `0` afterwards.
By default the finality confirmations of the network's `env::Config` will be applied and no finality confirmations will be persisted on disk in the config file.
It is however possible to set finality confirmations in the config file for bitcoin and monero for power users at their own risk.
If set the defaults will be overwritten with the parameter from the config file upon startup.
To run the ASB on testnet, one actively has to provide the `--testnet` flag.
Mainnet and testnet data and config are separated into sub-folders, i.e. `{data/config-dir}/asb/testnet` and `{data-dir}/asb/mainnet`.
The initial setup is also per network. If (default) config for the network cannot be found the initial setup is triggered.
Startup includes network check to ensure the bitcoin/monero network in config file is the same as the one in the `env::Config`.
Note: Wallet initialization is done with the network set in the `env::Config`, the network saved in the config file is just to indicate what network the config file is for.
This includes testing CLI commandline args
Clap's `default_value_with` actually did not work on `Subcommand`s because the parent's flags were not picked up.
This was fixed by changing parameters dependent on testnet/mainnet to options.
This problem should have been detected by tests, that's why the command line parameter tests were finally (re-)added.
Thanks to @rishflab for some pre-work for this.
In order to allow people to plug into public nodes / be more flexible with their own setup we now enforce specifying the monero daemon port to be used by the `monero-wallet-rpc`.
In the past we had problems with flags/parameter changes several times, where on instance was changed, buy another one was missed. This should mitigate this problem.
This patch introduces structs for all duplicated parameters and uses flatten to only have one point for changes.
Additionally removes all mentions of `alice` from the commands / variables. This code is on an application level and should not be concerned with swap protocol roles.
Introduces a minimum buy Bitcoin amount similar to the maximum amount already present.
For the CLI the minimum amount is enforced by waiting until at least the minimum is available as max-giveable amount.
Max-buy and spread is not something that one would configure on every run.
More convenient to keep this in the config.
The max-buy Bitcoin value was adapted to `0.02` which is more reasonable for mainnet.
Activated feature `serde-float` to serialize the spread (Decimal) as float instead of string.
```
...
[maker]
max_buy_btc = 0.02
ask_spread = 0.02
```
Adds `cancel`, `refund`, `punish`, `redeem` and `safely-abort` commands to the ASB that can be used to trigger the specific scenario for the swap by ID.
In the production code it is a weird indirection that we load the state and then pass in the state and the database.
In the tests we have one additional load by doing it inside the command, but loading from the db is not expensive.
Move Alice's spot price logic into a dedicated network behaviour that handles all the logic.
The new behaviour encapsulates the complete state necessary for spot price request decision making.
The network behaviour cannot handle asynchronous calls, thus the balance is managed inside the spot price and has to updated regularly from the outside to ensure the spot price balance check has up to date data.
At the moment the balance is updated upon an incoming quote requests.
Code that is relevant for both ASB and CLI remains in the `network::spot_price` module (e.g. `network::spot_price::Error`).
Resume-only is a maintenance mode where no swaps are accepted but unfinished swaps are resumed.
This is achieve by ignoring incoming spot-price requests (that would lead to execution setup) in the event-loop.
Electrum has an estimate-fee feature which takes as input the block you want a tx to be included.
The result is a recommendation of BTC/vbyte.
Using this recommendation and the knowledge about the size of our transactions we compute an appropriate fee.
The size of the transactions were taken from real transactions as published on bitcoin testnet.
Note: in reality these sizes might fluctuate a bit but not for much.
Using the same default directory as data-/config-dir has caused unwanted side effects when running both applications on the same machine.
Use these directory names:
- ASB: xmr-btc-swap-asb
- CLI: xmr-btc-swap-cli
Since the functionality is now application specific the respective functions were moved into the appropriate module of the application.
This PR does a few things.
* It adds a TorTransport which either dials through Tor's socks5 proxy or via clearnet.
* It enables ASB to register hidden services for each network it is listening on. We assume that we only care about different ports and re-use the same onion-address for all of them. The ASB requires to have access to Tor's control port.
* It adds support to dial through a local Tor socks5 proxy. We assume that Tor is always available on localhost. Swap cli only requires Tor to be running so that it can send messages via Tor's socks5 proxy.
* It adds a new e2e test which swaps through Tor. For this we assume that Tor is currently running on localhost. All other tests are running via clear net.
442: Minor cleanups towards implementing a Monero wallet for local signing r=thomaseizinger a=thomaseizinger
Extracted out of #434.
Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
- Listen on both tcp and websockets as default
- Listening addresses in config as array
- Configure fallback transport using `or_transport` - if listening on a given address fails on WS, we fall back to TCP.
405: Concurrent swaps with same peer r=da-kami a=da-kami
Fixes#367
- [x] Concurrent swaps with same peer
Not sure how much more time I should invest into this. We could just merge the current state and then do improvements on top...?
Improvements:
- [x] Think `// TODO: Remove unnecessary swap-id check` through and remove it
- [x] Add concurrent swap test, multiple swaps with same Bob
- [ ] Save swap messages without matching swap in execution in the database
- [ ] Assert the balances in the new concurrent swap tests
- [ ] ~~Add concurrent swap test, multiple swaps with different Bobs~~
- [ ] ~~Send swap-id in separate message, not on top of `Message0`~~
Co-authored-by: Daniel Karzel <daniel@comit.network>
- Swap-id is exchanged during execution setup. CLI (Bob) sends the swap-id to be used in his first message.
- Transfer poof and encryption signature messages include the swap-id so it can be properly associated with the correct swap.
- ASB: Encryption signatures are associated with swaps by swap-id, not peer-id.
- ASB: Transfer proofs are still associated to peer-ids (because they have to be sent to the respective peer), but the ASB can buffer multiple
- CLI: Incoming transfer proofs are checked for matching swap-id. If a transfer proof with a different swap-id than the current executing swap is received it will be ignored. We can change this to saving into the database.
Includes concurrent swap tests with the same Bob.
- One test that pauses and starts an additional swap after the transfer proof was received. Results in both swaps being redeemed after resuming the first swap.
- One test that pauses and starts an additional swap before the transfer proof is sent (just after BTC locked). Results in the second swap redeeming and the first swap being refunded (because the transfer proof on Bob's side is lost). Once we store transfer proofs that we receive during executing a different swap into the database both swaps should redeem.
Note that the monero harness was adapted to allow creating wallets with multiple outputs, which is needed for Alice.
EnvFilter is applied globally. This means you cannot log at INFO level
to the terminal and at DEBUG level to log files. To get a around this
limitation I had to implement the layer trait on a new type and filter
in the on_event() trait method. Each swap has its own log file denoted
by its swap_id. The logger appends to the existing file when resuming a
swap.
Closes#278
396: Remove default connection details from CLI r=thomaseizinger a=rishflab
Connecting buyers to us by default is not consistent with our vision of
a decentralised network of sellers.
Closes#395
Co-authored-by: rishflab <rishflab@hotmail.com>
387: Improve the resilience of the network layer r=thomaseizinger a=thomaseizinger
We improve the resilience in two ways:
1. Use a timeout on Bob's side for the execution-setup.
2. Use the `bmrng` library to model the communication between Alice and Bob.
See commit messages for details.
Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
It might very well be that the cancel transaction is already published.
If that is the case, there is no point in failing the command. We simply
transition to cancel and exit normally.
The reason this comes up now is because Alice now properly waits for
the cancel timelock as well and publishes the cancel transaction first.
Ultimately, she should not do that because there is no benefit to her
unless she can also publish the punish transaction.
This allows loading the seller-peer-id from the database upon resuming a swap.
Thus, the parameters `--seller-peer-id` is removed for the `resume` command.
Other than the peer-id the multi address of a seller can change and thus is
still a parameter. This parameter might become optional once we add DHT support.
370: No Bitcoin deposit for Alice r=da-kami a=da-kami
The message to deposit Bitcoin only applies to Bob, not Alice.
Alice does not require any initial Bitcoin.
Co-authored-by: Daniel Karzel <daniel@comit.network>
The swap should not be concerned with connection handling. This is
the responsibility of the overall application.
All but the execution-setup NetworkBehaviour are `request-response`
behaviours. These have built-in functionality to automatically emit
a dial attempt in case we are not connected at the time we want to
send a message. We remove all of the manual dialling code from the
swap in favor of this behaviour.
Additionally, we make sure to establish a connection as soon as the
EventLoop gets started. In case we ever loose the connection to Alice,
we try to re-establish it.
351: Show the actual BTC amount and fee to be swapped r=da-kami a=da-kami
We got user feedback, that it is confusing that the amount "found" in the wallet does not match the amount actually being swapped, thus with this PR we explicitly display the amount swapped and fees.
Co-authored-by: Daniel Karzel <daniel@comit.network>
Since Alice's refund scenario starts with generating the temporary wallet
from keys to claim the XMR which results in Alice' unloading the wallet.
Alice then loads her original wallet to be able to handle more swaps.
Since Alice is in the role of the long running daemon handling concurrent
swaps, the operation to close, claim and re-open her default wallet must
be atomic.
This PR adds an additional step, that sweeps all the refunded XMR back into
the default wallet. In order to ensure that this is possible, Alice has to
ensure that the locked XMR got enough confirmations.
These changes allow us to assert Alice's balance after refunding.
The execution params don't change throughout the lifetime of the
program. They can be set in the wallet at the very beginning.
This simplifies the interface of the wallet functions.
We achieve our optimizations in three ways:
1. Batching calls instead of making them individually.
To get access to the batch calls, we replace all our
calls to the HTTP interface with RPC calls.
2. Never directly make network calls based on function
calls on the wallet.
Instead, inquiring about the status of a script always
just returns information based on local data. With every
call, we check when we last refreshed the local data and
do so if the data is considered to be too old. This
interval is configurable.
3. Use electrum's notification feature to get updated
with the latest blockheight.
Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
Co-authored-by: Rishab Sharma <rishflab@hotmail.com>
Instead of spawning the swap inside the event loop we send the swap back
to the caller to be spawned. This means we no longer need the remote handle
that was only used in the tests.
This now properly logs the swap results in production.
It also gives us more control over Alice's swap in the tests.
The CLI has sensible default values for all parameters,
thus a config file is not really an advantage but just
keeps getting in our way, so re remove it.
Instead, we use a regular loop and extract everything into a function
that can be independently tested.
`backoff` would be useful to retry the actual call to the node.
In order to be able to re-connect on certain errors, we model
connection errors separately from parsing errors. We also change
the API of the whole module to no longer forward all errors to
the subscribers but instead, only update the subscribers with
either a latest rate or a permanent failure in case we exhausted
all our options to re-connect the websocket.
To model all of this properly, we introduce to sub-modules so that
each submodule can have their own `Error` type.
Resolves#297.
The type hints are generated from the field names. This has the
unfortunate consequence of the config field becoming file_path which
does not really make sense people working on the codebase.
The bitcoin::Wallet::sync_wallet function doesn't do anything else
other than delegating. As such, we have just as much information
about what went wrong inside this function as we have outside.
By moving the .context call into the function, we can avoid repeating
us on every call-site.
288: Switch to public stagenet node that works r=rishflab a=rishflab
The xmr.to node has been unreliable lately. The exan.tech node seems to
working.
@da-kami is following up with making this configurable. Lets get this in so we can get a release on Friday.
Co-authored-by: rishflab <rishflab@hotmail.com>
Instead of leaking the tokio::sync:⌚:Receiver type in our
return value, we create a newtype that implements the desired
interface. This allows us to get rid of the `RateService` structs
and instead implement `LatestRate` directly on top of this struct.
Given that `LatestRate` is only used within the event_loop module,
we move the definition of this type into there.
Previously, the user neither knew the price nor the maximum quantity
they could trade. We now request a quote from the user and display
it to them.
Fixes#255.
This reduces the overall amount of LoC that imports take up in our
codebase by almost 100.
It also makes merge-conflicts less likely because there is less
grouping together of imports that may lead to layout changes which
in turn can cause merge conflicts.