diff --git a/.github/workflows/build-release-binaries.yml b/.github/workflows/build-release-binaries.yml index a4a651e5..d3832088 100644 --- a/.github/workflows/build-release-binaries.yml +++ b/.github/workflows/build-release-binaries.yml @@ -45,12 +45,12 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout tagged commit - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.2 with: ref: ${{ github.event.release.target_commitish }} token: ${{ secrets.BOTTY_GITHUB_TOKEN }} - - uses: Swatinem/rust-cache@v1.3.0 + - uses: Swatinem/rust-cache@v2.0.0 - name: Install compiler for armhf arch if: matrix.target == 'armv7-unknown-linux-gnueabihf' @@ -67,7 +67,7 @@ jobs: run: target/${{ matrix.target }}/release/${{ matrix.bin }} --help # Remove once python 3 is the default - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v4 with: python-version: "3.x" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46246c84..8abde22a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.2 - - uses: Swatinem/rust-cache@v1.3.0 + - uses: Swatinem/rust-cache@v2.0.0 - name: Check formatting - uses: dprint/check@v2.0 + uses: dprint/check@v2.1 - name: Run clippy with default features run: cargo clippy --workspace --all-targets -- -D warnings @@ -42,9 +42,9 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.2 - - uses: Swatinem/rust-cache@v1.3.0 + - uses: Swatinem/rust-cache@v2.0.0 - name: Install compiler for armhf arch if: matrix.target == 'armv7-unknown-linux-gnueabihf' @@ -75,9 +75,9 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.2 - - uses: Swatinem/rust-cache@v1.3.0 + - uses: Swatinem/rust-cache@v2.0.0 - name: Build tests run: cargo build --tests --workspace --all-features @@ -111,9 +111,9 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v3.0.2 - - uses: Swatinem/rust-cache@v1.3.0 + - uses: Swatinem/rust-cache@v2.0.0 - name: Run test ${{ matrix.test_name }} run: cargo test --package swap --all-features --test ${{ matrix.test_name }} -- --nocapture diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index ee95935f..a87f323b 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -11,7 +11,7 @@ jobs: if: github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3.0.2 - name: Extract version from branch name id: extract-version diff --git a/.github/workflows/draft-new-release.yml b/.github/workflows/draft-new-release.yml index bab5c85a..d27791be 100644 --- a/.github/workflows/draft-new-release.yml +++ b/.github/workflows/draft-new-release.yml @@ -12,7 +12,7 @@ jobs: name: "Draft a new release" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3.0.2 with: token: ${{ secrets.BOTTY_GITHUB_TOKEN }} @@ -20,7 +20,7 @@ jobs: run: git checkout -b release/${{ github.event.inputs.version }} - name: Update changelog - uses: thomaseizinger/keep-a-changelog-new-release@1.2.1 + uses: thomaseizinger/keep-a-changelog-new-release@1.3.0 with: version: ${{ github.event.inputs.version }} changelogPath: CHANGELOG.md diff --git a/.github/workflows/preview-release.yml b/.github/workflows/preview-release.yml index a8207201..8499248f 100644 --- a/.github/workflows/preview-release.yml +++ b/.github/workflows/preview-release.yml @@ -10,7 +10,7 @@ jobs: name: Create preview release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2.4.0 + - uses: actions/checkout@v3.0.2 - name: Delete 'preview' release uses: larryjoelane/delete-release-action@v1.0.24 diff --git a/.gitignore b/.gitignore index c0b0db30..905e678b 100644 --- a/.gitignore +++ b/.gitignore @@ -157,3 +157,6 @@ flycheck_*.el .swap-db/ # End of https://www.toptal.com/developers/gitignore/api/rust,clion+all,emacs + +*.log +.vscode \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c09cdce..41243c57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,14 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Change Monero nodes to [Rino tool nodes](https://community.rino.io/nodes.html) -- Revert logs to use rfc3339 local time formatting. +- Update from monero v17.2.0 to monero v17.3.0 - Always write logs as JSON to files +- Change to UTC time for log messages, due to a bug causing no logging at all to be printed (linux/macos), and an [unsoundness issue](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/time/struct.LocalTime.html) with local time in [the time crate](https://github.com/time-rs/time/issues/293#issuecomment-748151025) +- Fix potential integer overflow in ASB when calculating maximum Bitcoin amount for Monero balance +- Reduce Monero locking transaction fee amount from 0.000030 to 0.000016 XMR, which is still double the current median fee as reported at [monero.how](https://www.monero.how/monero-transaction-fees) ### Added - Adjust quote based on Bitcoin balance. - If the max_buy_btc in the ASB config is higher than the available balance to trade it will return the max available balance discounting the locking fees for monero, in the case the balance is lower than the min_buy_btc config it will return 0 to the CLI. If the ASB returns a quote of 0 the CLI will not allow you continue with a trade. + If the max_buy_btc in the ASB config is higher than the available balance to trade, it will return the max available balance discounting the Monero locking fees. In the case the balance is lower than the min_buy_btc config it will return 0 to the CLI. If the ASB returns a quote of 0 the CLI will not allow you continue with a trade. - Reduce required confirmations for Bitcoin transactions from 2 to 1 +- Both the ASB and CLI now support the [Identify](https://github.com/libp2p/specs/blob/master/identify/README.md) protocol. This makes its version and network (testnet/mainnet) avaliable to others +- Display minimum BTC deposit required to cover the minimum quantity plus fee in the Swap CLI ## [0.10.2] - 2021-12-25 diff --git a/Cargo.lock b/Cargo.lock index 72ee11dc..25487a28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,9 +74,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "c91f1f46651137be86f3a2b9a8359f9ab421d04d941c62b5982e1ca21113adf9" [[package]] name = "arrayref" @@ -104,22 +104,22 @@ checksum = "9d6e24d2cce90c53b948c46271bfb053e4bdc2db9b5d3f65e20f8cf28a1b7fc3" [[package]] name = "async-compression" -version = "0.3.8" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443ccbb270374a2b1055fc72da40e1f237809cd6bb0e97e66d264cd138473a6" +checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" dependencies = [ "bzip2", "futures-core", "memchr", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "tokio", ] [[package]] name = "async-trait" -version = "0.1.52" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", @@ -136,7 +136,7 @@ dependencies = [ "futures-sink", "futures-util", "memchr", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", ] [[package]] @@ -189,7 +189,7 @@ dependencies = [ "futures-core", "getrandom 0.2.2", "instant", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "rand 0.8.3", "tokio", ] @@ -523,7 +523,6 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time 0.1.43", "winapi 0.3.9", ] @@ -573,8 +572,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b103d85ca6e209388771bfb7aa6b68a7aeec4afbf6f0a0264bfbf50360e5212e" dependencies = [ "crossterm", - "strum", - "strum_macros", + "strum 0.23.0", + "strum_macros 0.23.0", "unicode-width", ] @@ -832,9 +831,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.13.0" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ "darling_core", "darling_macro", @@ -842,9 +841,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.0" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c34d8efb62d0c2d7f60ece80f75e5c63c1588ba68032740494b0b9a996466e3" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", @@ -856,9 +855,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.13.0" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", @@ -897,9 +896,9 @@ dependencies = [ [[package]] name = "dialoguer" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d6b4fabcd9e97e1df1ae15395ac7e49fb144946a0d453959dc2696273b9da" +checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" dependencies = [ "console", "tempfile", @@ -1029,7 +1028,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" dependencies = [ - "heck", + "heck 0.3.2", "proc-macro2", "quote", "syn", @@ -1252,7 +1251,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "pin-utils", "slab", ] @@ -1394,6 +1393,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.18" @@ -1502,9 +1507,9 @@ checksum = "05842d0d43232b23ccb7060ecb0f0626922c21f30012e97b767b30afd4a5d4b9" [[package]] name = "hyper" -version = "0.14.18" +version = "0.14.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" dependencies = [ "bytes", "futures-channel", @@ -1516,7 +1521,7 @@ dependencies = [ "httparse", "httpdate", "itoa 1.0.1", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "socket2 0.4.0", "tokio", "tower-service", @@ -1777,6 +1782,7 @@ dependencies = [ "lazy_static", "libp2p-core", "libp2p-dns", + "libp2p-identify", "libp2p-metrics", "libp2p-mplex", "libp2p-noise", @@ -1840,12 +1846,29 @@ dependencies = [ "trust-dns-resolver", ] +[[package]] +name = "libp2p-identify" +version = "0.31.0" +source = "git+https://github.com/libp2p/rust-libp2p.git#6d3ab8a3debe8d69dcd004173999732f12d0da96" +dependencies = [ + "futures", + "libp2p-core", + "libp2p-swarm", + "log", + "lru 0.6.6", + "prost", + "prost-build", + "smallvec", + "wasm-timer", +] + [[package]] name = "libp2p-metrics" version = "0.1.0" source = "git+https://github.com/libp2p/rust-libp2p.git#6d3ab8a3debe8d69dcd004173999732f12d0da96" dependencies = [ "libp2p-core", + "libp2p-identify", "libp2p-ping", "libp2p-swarm", "open-metrics-client", @@ -1935,7 +1958,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "lru", + "lru 0.7.0", "rand 0.7.3", "smallvec", "unsigned-varint", @@ -2106,6 +2129,15 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "lru" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" +dependencies = [ + "hashbrown", +] + [[package]] name = "lru" version = "0.7.0" @@ -2139,6 +2171,15 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.8" @@ -2252,7 +2293,7 @@ dependencies = [ "testcontainers 0.12.0", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -2286,7 +2327,7 @@ dependencies = [ "rand 0.7.3", "testcontainers 0.12.0", "tokio", - "tracing-subscriber", + "tracing-subscriber 0.2.25", ] [[package]] @@ -2500,9 +2541,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.7.2" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" [[package]] name = "opaque-debug" @@ -2598,9 +2639,9 @@ dependencies = [ [[package]] name = "pem" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" dependencies = [ "base64 0.13.0", ] @@ -2632,11 +2673,11 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.27" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" +checksum = "3ef0f924a5ee7ea9cbcea77529dba45f8a9ba9f622419fe3386ca581a3ae9d5a" dependencies = [ - "pin-project-internal 0.4.27", + "pin-project-internal 0.4.30", ] [[package]] @@ -2650,9 +2691,9 @@ dependencies = [ [[package]] name = "pin-project-internal" -version = "0.4.27" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" +checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" dependencies = [ "proc-macro2", "quote", @@ -2678,9 +2719,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -2774,11 +2815,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -2818,7 +2859,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603" dependencies = [ "bytes", - "heck", + "heck 0.3.2", "itertools", "log", "multimap", @@ -3167,9 +3208,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" dependencies = [ "base64 0.13.0", "bytes", @@ -3187,7 +3228,7 @@ dependencies = [ "log", "mime", "percent-encoding", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "rustls 0.20.2", "rustls-pemfile", "serde", @@ -3196,13 +3237,14 @@ dependencies = [ "tokio", "tokio-rustls 0.23.1", "tokio-socks", - "tokio-util 0.6.9", + "tokio-util 0.7.2", + "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "webpki-roots 0.22.2", - "winreg 0.7.0", + "winreg 0.10.1", ] [[package]] @@ -3232,9 +3274,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.22.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37baa70cf8662d2ba1c1868c5983dda16ef32b105cce41fb5c47e72936a90b3" +checksum = "8fc129ab6000ab4037e7718703cdeab82a12c4ee23a238658f55372d80ef2b05" dependencies = [ "arrayvec 0.7.2", "num-traits", @@ -3243,9 +3285,9 @@ dependencies = [ [[package]] name = "rust_decimal_macros" -version = "1.22.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184abaf7b434800e1a5a8aad3ebc8cd7498df33af72d65371d797a264713a59b" +checksum = "56a77009c5812aeb7843b43a997ac268bd9c524b4331bf57b48ef097f30c9ad7" dependencies = [ "quote", "rust_decimal", @@ -3324,9 +3366,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "e7522c9de787ff061458fe9a829dc790a3f5b22dc571694fc5883f448b94d9a9" dependencies = [ "base64 0.13.0", ] @@ -3356,7 +3398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4da5fcb054c46f5a5dff833b129285a93d3f0179531735e6c866e8cc307d2020" dependencies = [ "futures", - "pin-project 0.4.27", + "pin-project 0.4.30", "static_assertions", ] @@ -3487,9 +3529,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.136" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "e590c437916fb6b221e1d00df6e3294f3fccd70ca7e92541c475d6ed6ef5fee2" dependencies = [ "serde_derive", ] @@ -3516,9 +3558,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "34b5b8d809babe02f538c2cfec6f2c1ed10804c0e5a6a041a049a4f5588ccc2e" dependencies = [ "proc-macro2", "quote", @@ -3527,9 +3569,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.74" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ "indexmap", "itoa 1.0.1", @@ -3539,32 +3581,31 @@ dependencies = [ [[package]] name = "serde_urlencoded" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 0.4.7", + "itoa 1.0.1", "ryu", "serde", ] [[package]] name = "serde_with" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" dependencies = [ - "rustversion", "serde", "serde_with_macros", ] [[package]] name = "serde_with_macros" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c1fcca18d55d1763e1c16873c4bde0ac3ef75179a28c7b372917e0494625be" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling", "proc-macro2", @@ -3853,7 +3894,7 @@ checksum = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5" dependencies = [ "dotenv", "either", - "heck", + "heck 0.3.2", "hex", "once_cell", "proc-macro2", @@ -3929,7 +3970,7 @@ version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ - "heck", + "heck 0.3.2", "proc-macro-error", "proc-macro2", "quote", @@ -3941,8 +3982,14 @@ name = "strum" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.0", ] [[package]] @@ -3951,7 +3998,20 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00ad150e9d51e33e8142984f577662c1324d49f3be45ed37bac8645fdcbe0fe5" dependencies = [ - "heck", + "heck 0.3.2", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "strum_macros" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" +dependencies = [ + "heck 0.4.0", "proc-macro2", "quote", "rustversion", @@ -4021,22 +4081,22 @@ dependencies = [ "spectral", "sqlx", "structopt", - "strum", + "strum 0.24.1", "tempfile", "testcontainers 0.12.0", "thiserror", - "time 0.3.7", + "time 0.3.11", "tokio", "tokio-socks", "tokio-tar", "tokio-tungstenite", - "tokio-util 0.7.0", + "tokio-util 0.7.2", "toml", "torut", "tracing", "tracing-appender", "tracing-futures", - "tracing-subscriber", + "tracing-subscriber 0.3.15", "url", "uuid", "vergen", @@ -4046,13 +4106,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.73" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -4133,18 +4193,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" dependencies = [ "proc-macro2", "quote", @@ -4153,9 +4213,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" dependencies = [ "once_cell", ] @@ -4172,10 +4232,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.7" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" +checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" dependencies = [ + "itoa 1.0.1", "libc", "num_threads", ] @@ -4218,7 +4279,7 @@ dependencies = [ "num_cpus", "once_cell", "parking_lot 0.11.2", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "signal-hook-registry", "tokio-macros", "winapi 0.3.9", @@ -4276,7 +4337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c535f53c0cfa1acace62995a8994fc9cc1f12d202420da96ff306ee24d576469" dependencies = [ "futures-core", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "tokio", ] @@ -4322,29 +4383,29 @@ dependencies = [ "futures-core", "futures-sink", "log", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "tokio", + "tracing", ] [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] @@ -4375,32 +4436,32 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if 1.0.0", - "pin-project-lite 0.2.8", + "pin-project-lite 0.2.9", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-appender" -version = "0.1.2" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9965507e507f12c8901432a33e31131222abac31edd90cabbcf85cf544b7127a" +checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" dependencies = [ - "chrono", "crossbeam-channel", - "tracing-subscriber", + "time 0.3.11", + "tracing-subscriber 0.3.15", ] [[package]] name = "tracing-attributes" -version = "0.1.18" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" dependencies = [ "proc-macro2", "quote", @@ -4409,11 +4470,12 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ - "lazy_static", + "once_cell", + "valuable", ] [[package]] @@ -4441,9 +4503,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" dependencies = [ "serde", "tracing-core", @@ -4458,12 +4520,30 @@ dependencies = [ "ansi_term 0.12.1", "chrono", "lazy_static", - "matchers", + "matchers 0.0.1", + "regex", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b" +dependencies = [ + "ansi_term 0.12.1", + "matchers 0.1.0", + "once_cell", "regex", "serde", "serde_json", "sharded-slab", "thread_local", + "time 0.3.11", "tracing", "tracing-core", "tracing-log", @@ -4576,6 +4656,12 @@ dependencies = [ "matches", ] +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + [[package]] name = "unicode-normalization" version = "0.1.17" @@ -4658,14 +4744,20 @@ checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" [[package]] name = "uuid" -version = "0.8.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" dependencies = [ "getrandom 0.2.2", "serde", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.11" @@ -4680,18 +4772,18 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "vergen" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0c9f8387e118573859ae0e6c6fbdfa41bd1f4fbea451b0b8c5a81a3b8bc9e0" +checksum = "4db743914c971db162f35bf46601c5a63ec4452e61461937b4c1ab817a60c12e" dependencies = [ "anyhow", "cfg-if 1.0.0", - "chrono", "enum-iterator", "getset", "git2", "rustversion", "thiserror", + "time 0.3.11", ] [[package]] @@ -4989,9 +5081,9 @@ dependencies = [ [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi 0.3.9", ] diff --git a/docs/asb/README.md b/docs/asb/README.md index e39375a9..e0991d8d 100644 --- a/docs/asb/README.md +++ b/docs/asb/README.md @@ -48,7 +48,7 @@ For example: ```toml [network] -rendezvous_point = "/dnsaddr/rendezvous.coblox.tech/p2p/12D3KooWQUt9DkNZxEn2R5ymJzWj15MpG6mTW84kyd8vDaRZi46o" +rendezvous_point = "/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE" external_addresses = ["/dns4/example.com/tcp/9939"] ``` diff --git a/docs/cli/README.md b/docs/cli/README.md index 82de15d4..d95d90ef 100644 --- a/docs/cli/README.md +++ b/docs/cli/README.md @@ -100,7 +100,7 @@ OPTIONS: --tor-socks5-port Your local Tor socks5 proxy port [default: 9050] ``` -Running `swap --testnet list-sellers --rendezvous-point /dnsaddr/rendezvous.coblox.tech/p2p/12D3KooWQUt9DkNZxEn2R5ymJzWj15MpG6mTW84kyd8vDaRZi46o` will give you something like: +Running `swap --testnet list-sellers --rendezvous-point /dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE` will give you something like: ``` Connected to rendezvous point, discovering nodes in 'xmr-btc-swap-testnet' namespace ... diff --git a/docs/cli/discover_and_take.sh b/docs/cli/discover_and_take.sh index af250951..6aca6475 100755 --- a/docs/cli/discover_and_take.sh +++ b/docs/cli/discover_and_take.sh @@ -8,7 +8,7 @@ # 4th param: Your bech32 Bitcoin testnet address that will be used for any change output (e.g. refund scenario or when swapping an amount smaller than the transferred BTC) # # Example usage: -# discover_and_take.sh "PATH/TO/swap" "/dnsaddr/rendezvous.coblox.tech/p2p/12D3KooWQUt9DkNZxEn2R5ymJzWj15MpG6mTW84kyd8vDaRZi46o" "YOUR_XMR_STAGENET_ADDRESS" "YOUR_BECH32_BITCOIN_TESTNET_ADDRESS" +# discover_and_take.sh "PATH/TO/swap" "/dns4/discover.unstoppableswap.net/tcp/8888/p2p/12D3KooWA6cnqJpVnreBVnoro8midDL9Lpzmg8oJPoAGi7YYaamE" "YOUR_XMR_STAGENET_ADDRESS" "YOUR_BECH32_BITCOIN_TESTNET_ADDRESS" CLI_PATH=$1 RENDEZVOUS_POINT=$2 diff --git a/swap/Cargo.toml b/swap/Cargo.toml index c631260a..bb66fcbf 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -31,10 +31,10 @@ ed25519-dalek = "1" futures = { version = "0.3", default-features = false } hex = "0.4" itertools = "0.10" -libp2p = { git = "https://github.com/libp2p/rust-libp2p.git", default-features = false, features = [ "tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response", "websocket", "ping", "rendezvous" ] } +libp2p = { git = "https://github.com/libp2p/rust-libp2p.git", default-features = false, features = [ "tcp-tokio", "yamux", "mplex", "dns-tokio", "noise", "request-response", "websocket", "ping", "rendezvous", "identify" ] } monero = { version = "0.12", features = [ "serde_support" ] } monero-rpc = { path = "../monero-rpc" } -pem = "1.0" +pem = "1.1" proptest = "1" qrcode = "0.12" rand = "0.8" @@ -50,7 +50,7 @@ sha2 = "0.9" sigma_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "ed25519", "serde" ] } sqlx = { version = "0.5", features = [ "sqlite", "runtime-tokio-rustls", "offline" ] } structopt = "0.3" -strum = { version = "0.23", features = [ "derive" ] } +strum = { version = "0.24", features = [ "derive" ] } thiserror = "1" time = "0.3" tokio = { version = "1", features = [ "rt-multi-thread", "time", "macros", "sync", "process", "fs", "net" ] } @@ -60,11 +60,11 @@ tokio-util = { version = "0.7", features = [ "io", "codec" ] } toml = "0.5" torut = { version = "0.2", default-features = false, features = [ "v3", "control" ] } tracing = { version = "0.1", features = [ "attributes" ] } -tracing-appender = "0.1" +tracing-appender = "0.2" tracing-futures = { version = "0.2", features = [ "std-future", "futures-03" ] } -tracing-subscriber = { version = "0.2", default-features = false, features = [ "fmt", "ansi", "env-filter", "chrono", "tracing-log", "json" ] } +tracing-subscriber = { version = "0.3", default-features = false, features = [ "fmt", "ansi", "env-filter", "time", "tracing-log", "json" ] } url = { version = "2", features = [ "serde" ] } -uuid = { version = "0.8", features = [ "serde", "v4" ] } +uuid = { version = "1.1", features = [ "serde", "v4" ] } void = "1" [target.'cfg(not(windows))'.dependencies] @@ -86,5 +86,5 @@ tempfile = "3" testcontainers = "0.12" [build-dependencies] -vergen = { version = "6", default-features = false, features = [ "git", "build" ] } +vergen = { version = "7", default-features = false, features = [ "git", "build" ] } anyhow = "1" diff --git a/swap/src/asb/command.rs b/swap/src/asb/command.rs index 7780fc56..9355568e 100644 --- a/swap/src/asb/command.rs +++ b/swap/src/asb/command.rs @@ -276,7 +276,7 @@ pub enum RawCommand { WithdrawBtc { #[structopt( long = "amount", - help = "Optionally specify the amount of Bitcoin to be withdrawn. If not specified the wallet will be drained." + help = "Optionally specify the amount of Bitcoin to be withdrawn. If not specified the wallet will be drained. Amount must be specified in quotes with denomination, e.g `--amount '0.1 BTC'`" )] amount: Option, #[structopt(long = "address", help = "The address to receive the Bitcoin.")] diff --git a/swap/src/asb/event_loop.rs b/swap/src/asb/event_loop.rs index 1a06d95f..9248a324 100644 --- a/swap/src/asb/event_loop.rs +++ b/swap/src/asb/event_loop.rs @@ -326,11 +326,13 @@ where .ask() .context("Failed to compute asking price")?; - let max_bitcoin_for_monero = self - .monero_wallet - .get_balance() - .await? - .max_bitcoin_for_price(ask_price); + let xmr = self.monero_wallet.get_balance().await?; + + let max_bitcoin_for_monero = xmr.max_bitcoin_for_price(ask_price).ok_or_else(|| { + anyhow::anyhow!("Bitcoin price ({}) x Monero ({}) overflow", ask_price, xmr) + })?; + + tracing::debug!(%ask_price, %xmr, %max_bitcoin_for_monero); if min_buy > max_bitcoin_for_monero { tracing::warn!( diff --git a/swap/src/asb/network.rs b/swap/src/asb/network.rs index d24660b9..70c7f861 100644 --- a/swap/src/asb/network.rs +++ b/swap/src/asb/network.rs @@ -13,6 +13,7 @@ use libp2p::core::connection::ConnectionId; use libp2p::core::muxing::StreamMuxerBox; use libp2p::core::transport::Boxed; use libp2p::dns::TokioDnsConfig; +use libp2p::identify::{Identify, IdentifyConfig, IdentifyEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::request_response::{RequestId, ResponseChannel}; use libp2p::swarm::{ @@ -111,6 +112,7 @@ pub mod behaviour { pub swap_setup: alice::Behaviour, pub transfer_proof: transfer_proof::Behaviour, pub encrypted_signature: encrypted_signature::Behaviour, + pub identify: Identify, /// Ping behaviour that ensures that the underlying network connection /// is still alive. If the ping fails a connection close event @@ -128,8 +130,14 @@ pub mod behaviour { latest_rate: LR, resume_only: bool, env_config: env::Config, + identify_params: (identity::Keypair, XmrBtcNamespace), rendezvous_params: Option<(identity::Keypair, PeerId, Multiaddr, XmrBtcNamespace)>, ) -> Self { + let agentVersion = format!("asb/{} ({})", env!("CARGO_PKG_VERSION"), identify_params.1); + let protocolVersion = "/comit/xmr/btc/1.0.0".to_string(); + let identifyConfig = IdentifyConfig::new(protocolVersion, identify_params.0.public()) + .with_agent_version(agentVersion); + Self { rendezvous: libp2p::swarm::toggle::Toggle::from(rendezvous_params.map( |(identity, rendezvous_peer_id, rendezvous_address, namespace)| { @@ -153,6 +161,7 @@ pub mod behaviour { transfer_proof: transfer_proof::alice(), encrypted_signature: encrypted_signature::alice(), ping: Ping::new(PingConfig::new().with_keep_alive(true)), + identify: Identify::new(identifyConfig), } } } @@ -163,6 +172,12 @@ pub mod behaviour { } } + impl From for OutEvent { + fn from(_: IdentifyEvent) -> Self { + OutEvent::Other + } + } + impl From for OutEvent { fn from(event: libp2p::rendezvous::client::Event) -> Self { OutEvent::Rendezvous(event) diff --git a/swap/src/asb/tracing.rs b/swap/src/asb/tracing.rs index dc3f7cca..c21c1e70 100644 --- a/swap/src/asb/tracing.rs +++ b/swap/src/asb/tracing.rs @@ -1,6 +1,6 @@ use anyhow::Result; use tracing_subscriber::filter::LevelFilter; -use tracing_subscriber::fmt::time::ChronoLocal; +use tracing_subscriber::fmt::time::UtcTime; use tracing_subscriber::FmtSubscriber; pub fn init(level: LevelFilter, json_format: bool, timestamp: bool) -> Result<()> { @@ -14,7 +14,7 @@ pub fn init(level: LevelFilter, json_format: bool, timestamp: bool) -> Result<() .with_env_filter(format!("asb={},swap={}", level, level)) .with_writer(std::io::stderr) .with_ansi(is_terminal) - .with_timer(ChronoLocal::with_format("%F %T".to_owned())) + .with_timer(UtcTime::rfc_3339()) .with_target(false); match (json_format, timestamp) { diff --git a/swap/src/bin/asb.rs b/swap/src/bin/asb.rs index 23300f20..a0e9b5e3 100644 --- a/swap/src/bin/asb.rs +++ b/swap/src/bin/asb.rs @@ -136,6 +136,8 @@ async fn main() -> Result<()> { }; let kraken_rate = KrakenRate::new(config.maker.ask_spread, kraken_price_updates); + let namespace = XmrBtcNamespace::from_is_testnet(testnet); + let mut swarm = swarm::asb( &seed, config.maker.min_buy_btc, @@ -143,16 +145,8 @@ async fn main() -> Result<()> { kraken_rate.clone(), resume_only, env_config, - config.network.rendezvous_point.map(|rendezvous_point| { - ( - rendezvous_point, - if testnet { - XmrBtcNamespace::Testnet - } else { - XmrBtcNamespace::Mainnet - }, - ) - }), + namespace, + config.network.rendezvous_point, )?; for listen in config.network.listen.clone() { diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index f3312f29..580b7d23 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -63,6 +63,7 @@ async fn main() -> Result<()> { monero_receive_address, monero_daemon_address, tor_socks5_port, + namespace, } => { let swap_id = Uuid::new_v4(); @@ -93,7 +94,12 @@ async fn main() -> Result<()> { .context("Seller address must contain peer ID")?; db.insert_address(seller_peer_id, seller.clone()).await?; - let behaviour = cli::Behaviour::new(seller_peer_id, env_config, bitcoin_wallet.clone()); + let behaviour = cli::Behaviour::new( + seller_peer_id, + env_config, + bitcoin_wallet.clone(), + (seed.derive_libp2p_identity(), namespace), + ); let mut swarm = swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?; swarm.behaviour_mut().add_address(seller_peer_id, seller); @@ -105,6 +111,8 @@ async fn main() -> Result<()> { let event_loop = tokio::spawn(event_loop.run()); let max_givable = || bitcoin_wallet.max_giveable(TxLock::script_size()); + let estimate_fee = |amount| bitcoin_wallet.estimate_fee(TxLock::weight(), amount); + let (amount, fees) = match determine_btc_to_swap( json, event_loop_handle.request_quote(), @@ -112,6 +120,7 @@ async fn main() -> Result<()> { || bitcoin_wallet.balance(), max_givable, || bitcoin_wallet.sync(), + estimate_fee, ) .await { @@ -271,6 +280,7 @@ async fn main() -> Result<()> { bitcoin_target_block, monero_daemon_address, tor_socks5_port, + namespace, } => { cli::tracing::init(debug, json, data_dir.join("logs"), Some(swap_id))?; @@ -298,7 +308,12 @@ async fn main() -> Result<()> { let seller_peer_id = db.get_peer_id(swap_id).await?; let seller_addresses = db.get_addresses(seller_peer_id).await?; - let behaviour = cli::Behaviour::new(seller_peer_id, env_config, bitcoin_wallet.clone()); + let behaviour = cli::Behaviour::new( + seller_peer_id, + env_config, + bitcoin_wallet.clone(), + (seed.derive_libp2p_identity(), namespace), + ); let mut swarm = swarm::cli(seed.derive_libp2p_identity(), tor_socks5_port, behaviour).await?; let our_peer_id = swarm.local_peer_id(); @@ -609,13 +624,14 @@ fn qr_code(value: &impl ToString) -> Result { Ok(qr_code) } -async fn determine_btc_to_swap( +async fn determine_btc_to_swap( json: bool, bid_quote: impl Future>, get_new_address: impl Future>, balance: FB, max_giveable_fn: FMG, sync: FS, + estimate_fee: FFE, ) -> Result<(bitcoin::Amount, bitcoin::Amount)> where TB: Future>, @@ -624,6 +640,8 @@ where FMG: Fn() -> TMG, TS: Future>, FS: Fn() -> TS, + FFE: Fn(bitcoin::Amount) -> TFE, + TFE: Future>, { tracing::debug!("Requesting quote"); let bid_quote = bid_quote.await?; @@ -651,8 +669,17 @@ where } loop { + let min_outstanding = bid_quote.min_quantity - max_giveable; + let min_fee = estimate_fee(min_outstanding).await?; + let min_deposit = min_outstanding + min_fee; + + tracing::info!( + "Deposit at least {} to cover the min quantity with fee!", + min_deposit + ); tracing::info!( %deposit_address, + %min_deposit, %max_giveable, %minimum_amount, %maximum_amount, @@ -684,9 +711,7 @@ where let balance = balance().await?; let fees = balance - max_giveable; - let max_accepted = bid_quote.max_quantity; - let btc_swap_amount = min(max_giveable, max_accepted); Ok((btc_swap_amount, fees)) @@ -752,6 +777,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ) .await .unwrap(); @@ -763,7 +789,8 @@ mod tests { assert_eq!( writer.captured(), r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC + INFO swap: Deposit at least 0.00001000 BTC to cover the min quantity with fee! + INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC INFO swap: Received Bitcoin new_balance=0.00100000 BTC max_giveable=0.00090000 BTC " ); @@ -787,6 +814,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ) .await .unwrap(); @@ -798,14 +826,15 @@ mod tests { assert_eq!( writer.captured(), r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC + INFO swap: Deposit at least 0.00001000 BTC to cover the min quantity with fee! + INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC INFO swap: Received Bitcoin new_balance=0.10010000 BTC max_giveable=0.10000000 BTC " ); } #[tokio::test] - async fn given_initial_balance_below_max_quantity_swaps_max_givable() { + async fn given_initial_balance_below_max_quantity_swaps_max_giveable() { let writer = capture_logs(LevelFilter::INFO); let givable = Arc::new(Mutex::new(MaxGiveable::new(vec![ Amount::from_btc(0.0049).unwrap(), @@ -822,6 +851,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ) .await .unwrap(); @@ -832,8 +862,7 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC -" + " INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC\n" ); } @@ -855,6 +884,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ) .await .unwrap(); @@ -865,8 +895,7 @@ mod tests { assert_eq!((amount, fees), (expected_amount, expected_fees)); assert_eq!( writer.captured(), - r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC -" + " INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.00000000 BTC maximum_amount=0.01000000 BTC\n" ); } @@ -888,6 +917,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ) .await .unwrap(); @@ -899,7 +929,8 @@ mod tests { assert_eq!( writer.captured(), r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC + INFO swap: Deposit at least 0.01001000 BTC to cover the min quantity with fee! + INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.01001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC " ); @@ -923,6 +954,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ) .await .unwrap(); @@ -934,7 +966,8 @@ mod tests { assert_eq!( writer.captured(), r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00010000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC + INFO swap: Deposit at least 0.00991000 BTC to cover the min quantity with fee! + INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.00991000 BTC max_giveable=0.00010000 BTC minimum_amount=0.01000000 BTC maximum_amount=184467440737.09551615 BTC INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC " ); @@ -963,6 +996,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ), ) .await @@ -972,10 +1006,12 @@ mod tests { assert_eq!( writer.captured(), r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC + INFO swap: Deposit at least 0.10001000 BTC to cover the min quantity with fee! + INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC INFO swap: Received Bitcoin new_balance=0.01010000 BTC max_giveable=0.01000000 BTC INFO swap: Deposited amount is less than `min_quantity` - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.01000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC + INFO swap: Deposit at least 0.09001000 BTC to cover the min quantity with fee! + INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.09001000 BTC max_giveable=0.01000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC " ); } @@ -1009,6 +1045,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ), ) .await @@ -1018,14 +1055,15 @@ mod tests { assert_eq!( writer.captured(), r" INFO swap: Received quote price=0.00100000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC - INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC + INFO swap: Deposit at least 0.10001000 BTC to cover the min quantity with fee! + INFO swap: Waiting for Bitcoin deposit deposit_address=1PdfytjS7C8wwd9Lq5o4x9aXA2YRqaCpH6 min_deposit=0.10001000 BTC max_giveable=0.00000000 BTC minimum_amount=0.10000000 BTC maximum_amount=184467440737.09551615 BTC INFO swap: Received Bitcoin new_balance=0.21000000 BTC max_giveable=0.20000000 BTC " ); } #[tokio::test] - async fn given_bid_quote_max_amount_0_return_errorq() { + async fn given_bid_quote_max_amount_0_return_error() { let givable = Arc::new(Mutex::new(MaxGiveable::new(vec![ Amount::from_btc(0.0001).unwrap(), Amount::from_btc(0.01).unwrap(), @@ -1041,6 +1079,7 @@ mod tests { result.give() }, || async { Ok(()) }, + |_| async { Ok(Amount::from_sat(1000)) }, ) .await .err() diff --git a/swap/src/bitcoin/lock.rs b/swap/src/bitcoin/lock.rs index c9efff2b..2f195ff7 100644 --- a/swap/src/bitcoin/lock.rs +++ b/swap/src/bitcoin/lock.rs @@ -11,6 +11,7 @@ use bitcoin::Script; use serde::{Deserialize, Serialize}; const SCRIPT_SIZE: usize = 34; +const TX_LOCK_WEIGHT: usize = 485; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct TxLock { @@ -161,6 +162,10 @@ impl TxLock { output: vec![tx_out], } } + + pub fn weight() -> usize { + TX_LOCK_WEIGHT + } } impl From for PartiallySignedTransaction { diff --git a/swap/src/cli/behaviour.rs b/swap/src/cli/behaviour.rs index 716b7951..2ca8448f 100644 --- a/swap/src/cli/behaviour.rs +++ b/swap/src/cli/behaviour.rs @@ -1,13 +1,15 @@ use crate::network::quote::BidQuote; +use crate::network::rendezvous::XmrBtcNamespace; use crate::network::swap_setup::bob; use crate::network::{encrypted_signature, quote, redial, transfer_proof}; use crate::protocol::bob::State2; use crate::{bitcoin, env}; use anyhow::{anyhow, Error, Result}; use libp2p::core::Multiaddr; +use libp2p::identify::{Identify, IdentifyConfig, IdentifyEvent}; use libp2p::ping::{Ping, PingConfig, PingEvent}; use libp2p::request_response::{RequestId, ResponseChannel}; -use libp2p::{NetworkBehaviour, PeerId}; +use libp2p::{identity, NetworkBehaviour, PeerId}; use std::sync::Arc; use std::time::Duration; @@ -64,6 +66,7 @@ pub struct Behaviour { pub transfer_proof: transfer_proof::Behaviour, pub encrypted_signature: encrypted_signature::Behaviour, pub redial: redial::Behaviour, + pub identify: Identify, /// Ping behaviour that ensures that the underlying network connection is /// still alive. If the ping fails a connection close event will be @@ -76,7 +79,13 @@ impl Behaviour { alice: PeerId, env_config: env::Config, bitcoin_wallet: Arc, + identify_params: (identity::Keypair, XmrBtcNamespace), ) -> Self { + let agentVersion = format!("cli/{} ({})", env!("CARGO_PKG_VERSION"), identify_params.1); + let protocolVersion = "/comit/xmr/btc/1.0.0".to_string(); + let identifyConfig = IdentifyConfig::new(protocolVersion, identify_params.0.public()) + .with_agent_version(agentVersion); + Self { quote: quote::cli(), swap_setup: bob::Behaviour::new(env_config, bitcoin_wallet), @@ -84,6 +93,7 @@ impl Behaviour { encrypted_signature: encrypted_signature::bob(), redial: redial::Behaviour::new(alice, Duration::from_secs(2)), ping: Ping::new(PingConfig::new().with_keep_alive(true)), + identify: Identify::new(identifyConfig), } } @@ -100,3 +110,9 @@ impl From for OutEvent { OutEvent::Other } } + +impl From for OutEvent { + fn from(_: IdentifyEvent) -> Self { + OutEvent::Other + } +} diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index ae793e1d..631cc00e 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -99,6 +99,7 @@ where monero_receive_address, monero_daemon_address, tor_socks5_port, + namespace: XmrBtcNamespace::from_is_testnet(is_testnet), }, } } @@ -179,6 +180,7 @@ where bitcoin_target_block, monero_daemon_address, tor_socks5_port, + namespace: XmrBtcNamespace::from_is_testnet(is_testnet), }, } } @@ -230,8 +232,8 @@ where data_dir: data::data_dir_from(data, is_testnet)?, cmd: Command::ListSellers { rendezvous_point, - namespace: rendezvous_namespace_from(is_testnet), tor_socks5_port, + namespace: XmrBtcNamespace::from_is_testnet(is_testnet), }, }, RawCommand::ExportBitcoinWallet { bitcoin } => { @@ -273,6 +275,7 @@ pub enum Command { monero_receive_address: monero::Address, monero_daemon_address: String, tor_socks5_port: u16, + namespace: XmrBtcNamespace, }, History, Config, @@ -292,6 +295,7 @@ pub enum Command { bitcoin_target_block: usize, monero_daemon_address: String, tor_socks5_port: u16, + namespace: XmrBtcNamespace, }, Cancel { swap_id: Uuid, @@ -562,14 +566,6 @@ mod data { } } -fn rendezvous_namespace_from(is_testnet: bool) -> XmrBtcNamespace { - if is_testnet { - XmrBtcNamespace::Testnet - } else { - XmrBtcNamespace::Mainnet - } -} - fn env_config_from(testnet: bool) -> env::Config { if testnet { env::Testnet::get_config() @@ -1212,6 +1208,7 @@ mod tests { .unwrap(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Testnet, }, } } @@ -1231,6 +1228,7 @@ mod tests { .unwrap(), monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Mainnet, }, } } @@ -1248,6 +1246,7 @@ mod tests { bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET_TESTNET, monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS_STAGENET.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Testnet, }, } } @@ -1264,6 +1263,7 @@ mod tests { bitcoin_target_block: DEFAULT_BITCOIN_CONFIRMATION_TARGET, monero_daemon_address: DEFAULT_MONERO_DAEMON_ADDRESS.to_string(), tor_socks5_port: DEFAULT_SOCKS5_PORT, + namespace: XmrBtcNamespace::Mainnet, }, } } diff --git a/swap/src/cli/tracing.rs b/swap/src/cli/tracing.rs index 3bafc229..a1cd77fb 100644 --- a/swap/src/cli/tracing.rs +++ b/swap/src/cli/tracing.rs @@ -1,10 +1,11 @@ use anyhow::Result; use std::option::Option::Some; use std::path::Path; +use time::format_description::well_known::Rfc3339; use tracing::subscriber::set_global_default; use tracing::{Event, Level, Subscriber}; use tracing_subscriber::fmt::format::{DefaultFields, Format, JsonFields}; -use tracing_subscriber::fmt::time::ChronoLocal; +use tracing_subscriber::fmt::time::UtcTime; use tracing_subscriber::layer::{Context, SubscriberExt}; use tracing_subscriber::{fmt, EnvFilter, FmtSubscriber, Layer, Registry}; use uuid::Uuid; @@ -15,7 +16,8 @@ pub fn init(debug: bool, json: bool, dir: impl AsRef, swap_id: Option, swap_id: Option, swap_id: Option, swap_id: Option { @@ -79,25 +80,25 @@ type StdErrJsonLayer = tracing_subscriber::fmt::Layer< fn() -> std::io::Stderr, >; -fn debug_terminal_printer() -> StdErrPrinter> { +fn debug_terminal_printer() -> StdErrPrinter>> { let is_terminal = atty::is(atty::Stream::Stderr); StdErrPrinter { inner: fmt::layer() .with_ansi(is_terminal) .with_target(false) - .with_timer(ChronoLocal::with_format("%F %T".to_owned())) + .with_timer(UtcTime::rfc_3339()) .with_writer(std::io::stderr), level: Level::DEBUG, } } -fn debug_json_terminal_printer() -> StdErrPrinter> { +fn debug_json_terminal_printer() -> StdErrPrinter>> { let is_terminal = atty::is(atty::Stream::Stderr); StdErrPrinter { inner: fmt::layer() .with_ansi(is_terminal) .with_target(false) - .with_timer(ChronoLocal::with_format("%F %T".to_owned())) + .with_timer(UtcTime::rfc_3339()) .json() .with_writer(std::io::stderr), level: Level::DEBUG, diff --git a/swap/src/monero.rs b/swap/src/monero.rs index bf3045ce..94555c8a 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -81,8 +81,8 @@ pub struct PublicViewKey(PublicKey); #[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd)] pub struct Amount(u64); -// Median tx fees on Monero as found here: https://www.monero.how/monero-transaction-fees, XMR 0.000_015 * 2 (to be on the safe side) -pub const MONERO_FEE: Amount = Amount::from_piconero(30000000); +// Median tx fees on Monero as found here: https://www.monero.how/monero-transaction-fees, XMR 0.000_008 * 2 (to be on the safe side) +pub const MONERO_FEE: Amount = Amount::from_piconero(16_000_000); impl Amount { pub const ZERO: Self = Self(0); @@ -95,22 +95,30 @@ impl Amount { Amount(amount) } + /// Return Monero Amount as Piconero. pub fn as_piconero(&self) -> u64 { self.0 } - pub fn max_bitcoin_for_price(&self, ask_price: bitcoin::Amount) -> bitcoin::Amount { - let piconero_minus_fee = self.as_piconero().saturating_sub(MONERO_FEE.as_piconero()); + /// Calculate the maximum amount of Bitcoin that can be bought at a given + /// asking price for this amount of Monero including the median fee. + pub fn max_bitcoin_for_price(&self, ask_price: bitcoin::Amount) -> Option { + let pico_minus_fee = self.as_piconero().saturating_sub(MONERO_FEE.as_piconero()); - if piconero_minus_fee == 0 { - return bitcoin::Amount::ZERO; + if pico_minus_fee == 0 { + return Some(bitcoin::Amount::ZERO); } - // There needs to be an offset for difference in zeroes beetween Piconeros and - // Satoshis - let piconero_calc = (piconero_minus_fee * ask_price.as_sat()) / PICONERO_OFFSET; + // safely convert the BTC/XMR rate to sat/pico + let ask_sats = Decimal::from(ask_price.as_sat()); + let pico_per_xmr = Decimal::from(PICONERO_OFFSET); + let ask_sats_per_pico = ask_sats / pico_per_xmr; - bitcoin::Amount::from_sat(piconero_calc) + let pico = Decimal::from(pico_minus_fee); + let max_sats = pico.checked_mul(ask_sats_per_pico)?; + let satoshi = max_sats.to_u64()?; + + Some(bitcoin::Amount::from_sat(satoshi)) } pub fn from_monero(amount: f64) -> Result { @@ -375,27 +383,88 @@ mod tests { } #[test] - fn geting_max_bitcoin_to_trade() { - let amount = Amount::parse_monero("10").unwrap(); - let bitcoin_price_sats = bitcoin::Amount::from_sat(382_900); + fn max_bitcoin_to_trade() { + // sanity check: if the asking price is 1 BTC / 1 XMR + // and we have μ XMR + fee + // then max BTC we can buy is μ + let ask = bitcoin::Amount::from_btc(1.0).unwrap(); - let monero_max_from_bitcoin = amount.max_bitcoin_for_price(bitcoin_price_sats); + let xmr = Amount::parse_monero("1.0").unwrap() + MONERO_FEE; + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); - assert_eq!( - bitcoin::Amount::from_sat(3_828_988), - monero_max_from_bitcoin - ); + assert_eq!(btc, bitcoin::Amount::from_btc(1.0).unwrap()); + + let xmr = Amount::parse_monero("0.5").unwrap() + MONERO_FEE; + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_btc(0.5).unwrap()); + + let xmr = Amount::parse_monero("2.5").unwrap() + MONERO_FEE; + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_btc(2.5).unwrap()); + + let xmr = Amount::parse_monero("420").unwrap() + MONERO_FEE; + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_btc(420.0).unwrap()); + + let xmr = Amount::parse_monero("0.00001").unwrap() + MONERO_FEE; + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_btc(0.00001).unwrap()); + + // other ask prices + + let ask = bitcoin::Amount::from_btc(0.5).unwrap(); + let xmr = Amount::parse_monero("2").unwrap() + MONERO_FEE; + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_btc(1.0).unwrap()); + + let ask = bitcoin::Amount::from_btc(2.0).unwrap(); + let xmr = Amount::parse_monero("1").unwrap() + MONERO_FEE; + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_btc(2.0).unwrap()); + + let ask = bitcoin::Amount::from_sat(382_900); + let xmr = Amount::parse_monero("10").unwrap(); + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_sat(3_828_993)); + + // example from https://github.com/comit-network/xmr-btc-swap/issues/1084 + // with rate from kraken at that time + let ask = bitcoin::Amount::from_sat(685_800); + let xmr = Amount::parse_monero("0.826286435921").unwrap(); + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(btc, bitcoin::Amount::from_sat(566_656)); + } + + #[test] + fn max_bitcoin_to_trade_overflow() { + let xmr = Amount::from_monero(30.0).unwrap(); + let ask = bitcoin::Amount::from_sat(728_688); + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); + + assert_eq!(bitcoin::Amount::from_sat(21_860_628), btc); + + let xmr = Amount::from_piconero(u64::MAX); + let ask = bitcoin::Amount::from_sat(u64::MAX); + let btc = xmr.max_bitcoin_for_price(ask); + + assert!(btc.is_none()); } #[test] fn geting_max_bitcoin_to_trade_with_balance_smaller_than_locking_fee() { - let monero = "0.00001"; - let amount = Amount::parse_monero(monero).unwrap(); - let bitcoin_price_sats = bitcoin::Amount::from_sat(382_900); + let ask = bitcoin::Amount::from_sat(382_900); + let xmr = Amount::parse_monero("0.00001").unwrap(); + let btc = xmr.max_bitcoin_for_price(ask).unwrap(); - let monero_max_from_bitcoin = amount.max_bitcoin_for_price(bitcoin_price_sats); - - assert_eq!(bitcoin::Amount::ZERO, monero_max_from_bitcoin); + assert_eq!(bitcoin::Amount::ZERO, btc); } use rand::rngs::OsRng; diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index 859b451b..0d3d3389 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -314,8 +314,13 @@ async fn wait_for_confirmations proof, - Err(jsonrpc::Error::JsonRpc(jsonrpc::JsonRpcError { code: -1, .. })) => { - tracing::warn!(%txid, "`monero-wallet-rpc` failed to fetch transaction, may need to be restarted"); + Err(jsonrpc::Error::JsonRpc(jsonrpc::JsonRpcError { + code: -1, + message, + data, + })) => { + tracing::debug!(message, ?data); + tracing::warn!(%txid, message, "`monero-wallet-rpc` failed to fetch transaction, may need to be restarted"); continue; } // TODO: Implement this using a generic proxy for each function call once https://github.com/thomaseizinger/rust-jsonrpc-client/issues/47 is fixed. diff --git a/swap/src/monero/wallet_rpc.rs b/swap/src/monero/wallet_rpc.rs index 18d66064..f3fbec90 100644 --- a/swap/src/monero/wallet_rpc.rs +++ b/swap/src/monero/wallet_rpc.rs @@ -18,17 +18,17 @@ use tokio_util::io::StreamReader; compile_error!("unsupported operating system"); #[cfg(target_os = "macos")] -const DOWNLOAD_URL: &str = "http://downloads.getmonero.org/cli/monero-mac-x64-v0.17.2.0.tar.bz2"; +const DOWNLOAD_URL: &str = "http://downloads.getmonero.org/cli/monero-mac-x64-v0.17.3.0.tar.bz2"; #[cfg(all(target_os = "linux", target_arch = "x86_64"))] -const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.17.2.0.tar.bz2"; +const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.17.3.0.tar.bz2"; #[cfg(all(target_os = "linux", target_arch = "arm"))] const DOWNLOAD_URL: &str = - "https://downloads.getmonero.org/cli/monero-linux-armv7-v0.17.2.0.tar.bz2"; + "https://downloads.getmonero.org/cli/monero-linux-armv7-v0.17.3.0.tar.bz2"; #[cfg(target_os = "windows")] -const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-win-x64-v0.17.2.0.zip"; +const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-win-x64-v0.17.3.0.zip"; #[cfg(any(target_os = "macos", target_os = "linux"))] const PACKED_FILE: &str = "monero-wallet-rpc"; diff --git a/swap/src/network/rendezvous.rs b/swap/src/network/rendezvous.rs index 5f8727c5..86a698a2 100644 --- a/swap/src/network/rendezvous.rs +++ b/swap/src/network/rendezvous.rs @@ -27,3 +27,13 @@ impl From for Namespace { } } } + +impl XmrBtcNamespace { + pub fn from_is_testnet(testnet: bool) -> XmrBtcNamespace { + if testnet { + XmrBtcNamespace::Testnet + } else { + XmrBtcNamespace::Mainnet + } + } +} diff --git a/swap/src/network/swarm.rs b/swap/src/network/swarm.rs index 8d4c7703..21bbfc4d 100644 --- a/swap/src/network/swarm.rs +++ b/swap/src/network/swarm.rs @@ -16,14 +16,15 @@ pub fn asb( latest_rate: LR, resume_only: bool, env_config: env::Config, - rendezvous_params: Option<(Multiaddr, XmrBtcNamespace)>, + namespace: XmrBtcNamespace, + rendezvous_point: Option, ) -> Result>> where LR: LatestRate + Send + 'static + Debug + Clone, { let identity = seed.derive_libp2p_identity(); - let rendezvous_params = if let Some((address, namespace)) = rendezvous_params { + let rendezvous_params = if let Some(address) = rendezvous_point { let peer_id = address .extract_peer_id() .context("Rendezvous node address must contain peer ID")?; @@ -39,6 +40,7 @@ where latest_rate, resume_only, env_config, + (identity.clone(), namespace), rendezvous_params, ); diff --git a/swap/src/tracing_ext.rs b/swap/src/tracing_ext.rs index 912187fd..6fd7eaba 100644 --- a/swap/src/tracing_ext.rs +++ b/swap/src/tracing_ext.rs @@ -41,7 +41,7 @@ impl MakeCapturingWriter { } } -impl MakeWriter for MakeCapturingWriter { +impl<'a> MakeWriter<'a> for MakeCapturingWriter { type Writer = CapturingWriter; fn make_writer(&self) -> Self::Writer { diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index b23201e0..e7971e66 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -19,6 +19,7 @@ use swap::bitcoin::{CancelTimelock, PunishTimelock, TxCancel, TxPunish, TxRedeem use swap::database::SqliteDatabase; use swap::env::{Config, GetConfig}; use swap::fs::ensure_directory_exists; +use swap::network::rendezvous::XmrBtcNamespace; use swap::network::swarm; use swap::protocol::alice::{AliceState, Swap}; use swap::protocol::bob::BobState; @@ -243,6 +244,7 @@ async fn start_alice( latest_rate, resume_only, env_config, + XmrBtcNamespace::Testnet, None, ) .unwrap(); @@ -469,18 +471,15 @@ impl BobParams { ) -> Result<(cli::EventLoop, cli::EventLoopHandle)> { let tor_socks5_port = get_port() .expect("We don't care about Tor in the tests so we get a free port to disable it."); + let identity = self.seed.derive_libp2p_identity(); let behaviour = cli::Behaviour::new( self.alice_peer_id, self.env_config, self.bitcoin_wallet.clone(), + (identity.clone(), XmrBtcNamespace::Testnet), ); - let mut swarm = swarm::cli( - self.seed.derive_libp2p_identity(), - tor_socks5_port, - behaviour, - ) - .await?; + let mut swarm = swarm::cli(identity.clone(), tor_socks5_port, behaviour).await?; swarm .behaviour_mut() .add_address(self.alice_peer_id, self.alice_address.clone());