diff --git a/.env.example b/.env.example index 4e32f36..babd46d 100644 --- a/.env.example +++ b/.env.example @@ -2,12 +2,14 @@ BITCOIN_ELECTRUM_RPC_URL="http://btc-electrum:7000" BITCOIN_ELECTRUM_RPC_USERNAME="user" BITCOIN_ELECTRUM_RPC_PASSWORD="" LITECOIN_ELECTRUM_RPC_URL="http://ltc-electrum:7000" +LITECOIN_MWEB_ELECTRUM_RPC_URL="http://ltc-mweb-electrum:7000" LITECOIN_ELECTRUM_RPC_USERNAME="user" LITECOIN_ELECTRUM_RPC_PASSWORD="" BITCOIN_ELECTRUM_SERVER_ADDRESS="" LITECOIN_ELECTRUM_SERVER_ADDRESS="" BITCOIN_WALLET_SEED="" LITECOIN_WALLET_SEED="" +LITECOIN_MWEB_WALLET_SEED="" MONERO_DAEMON_ADDRESS="" MONERO_RPC_URL="" @@ -17,10 +19,6 @@ MONERO_WALLET_SEED="" MONERO_WALLET_PASSWORD="" MONERO_WALLET_HEIGHT="" -NBXPLORER_URL="" -NBXPLORER_USERNAME="" -NBXPLORER_PASSWORD="" - KRAKEN_API_KEY="" KRAKEN_API_SECRET="" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 197e1f9..18be8cb 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,16 +25,33 @@ jobs: git pull echo "Starting..." - ELECTRUM_RPC_USERNAME="user" \ - ELECTRUM_RPC_PASSWORD="${{ secrets.ELECTRUM_RPC_PASSWORD }}" \ - BITCOIN_WALLET_SEED="${{ secrets.BITCOIN_WALLET_SEED }}" \ - MONERO_DAEMON_ADDRESS="${{ secrets.MONERO_DAEMON_ADDRESS }}" \ - MONERO_RPC_USERNAME="user" \ - MONERO_RPC_PASSWORD="${{ secrets.MONERO_RPC_PASSWORD }}" \ - MONERO_WALLET_SEED="${{ secrets.MONERO_WALLET_SEED }}" \ - MONERO_WALLET_PASSWORD="${{ secrets.MONERO_WALLET_PASSWORD }}" \ - MONERO_WALLET_HEIGHT="${{ secrets.MONERO_WALLET_HEIGHT }}" \ - KRAKEN_API_KEY="${{ secrets.KRAKEN_API_KEY }}" \ - KRAKEN_API_SECRET="${{ secrets.KRAKEN_API_SECRET }}" \ + BITCOIN_ELECTRUM_RPC_USERNAME=user \ + BITCOIN_ELECTRUM_RPC_PASSWORD=${{ secrets.BITCOIN_ELECTRUM_RPC_PASSWORD }} \ + LITECOIN_ELECTRUM_RPC_USERNAME=user \ + LITECOIN_ELECTRUM_RPC_PASSWORD=${{ secrets.LITECOIN_ELECTRUM_RPC_PASSWORD }} \ + BITCOIN_ELECTRUM_SERVER_ADDRESS=${{ secrets.BITCOIN_ELECTRUM_SERVER_ADDRESS }} \ + LITECOIN_ELECTRUM_SERVER_ADDRESS=${{ secrets.LITECOIN_ELECTRUM_SERVER_ADDRESS }} \ + BITCOIN_WALLET_SEED=${{ secrets.BITCOIN_WALLET_SEED }} \ + LITECOIN_WALLET_SEED=${{ secrets.LITECOIN_WALLET_SEED }} \ + LITECOIN_MWEB_WALLET_SEED=${{ secrets.LITECOIN_MWEB_WALLET_SEED }} \ + + MONERO_DAEMON_ADDRESS=${{ secrets.MONERO_DAEMON_ADDRESS }} \ + MONERO_RPC_URL=${{ secrets.MONERO_RPC_URL }} \ + MONERO_RPC_USERNAME=user \ + MONERO_RPC_PASSWORD=${{ secrets.MONERO_RPC_PASSWORD }} \ + MONERO_WALLET_SEED=${{ secrets.MONERO_WALLET_SEED }} \ + MONERO_WALLET_PASSWORD=${{ secrets.MONERO_WALLET_PASSWORD }} \ + MONERO_WALLET_HEIGHT=${{ secrets.MONERO_WALLET_HEIGHT }} \ + + KRAKEN_API_KEY=${{ secrets.KRAKEN_API_KEY }} \ + KRAKEN_API_SECRET=${{ secrets.KRAKEN_API_SECRET }} \ + + MAX_NETWORK_FEE_PERCENT=${{ secrets.MAX_NETWORK_FEE_PERCENT }} \ + MAX_SLIPPAGE_PERCENT=${{ secrets.MAX_SLIPPAGE_PERCENT }} \ + + BITCOIN_FEE_SOURCE=${{ secrets.BITCOIN_FEE_SOURCE }} \ + BITCOIN_FEE_RATE=${{ secrets.BITCOIN_FEE_RATE }} \ + LITECOIN_FEE_SOURCE=${{ secrets.LITECOIN_FEE_SOURCE }} \ + LITECOIN_FEE_RATE=${{ secrets.LITECOIN_FEE_RATE }} \ docker compose up -d --build EOF diff --git a/README.md b/README.md index c23d5a9..73f280a 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ Create a `.env` file as a copy of `.env.example` and set the values for the empt | `KRAKEN_API_KEY` | Yes | - | Your API key from Kraken. | | `KRAKEN_API_SECRET` | Yes | - | Your API secret from Kraken. | | `MONERO_DAEMON_ADDRESS` | Yes | - | The address of a Monero daemon you own or trust. | -| `BTC_ELECTRUM_SERVER_ADDRESS` | **No** | - | The address of a Bitcoin Electrum server you own or trust. E.g.: `localhost:50001:t` (no SSL) or `my.electrum.server:50001:s` (SSL). By leaving this blank you're letting Electrum select a random server for you, which may be a privacy concern. | -| `LTC_ELECTRUM_SERVER_ADDRESS` | **No** | - | The address of a Litecoin Electrum server you own or trust. E.g.: `localhost:50001:t` (no SSL) or `my.electrum.server:50001:s` (SSL). By leaving this blank you're letting Electrum select a random server for you, which may be a privacy concern. | +| `BITCOIN_ELECTRUM_SERVER_ADDRESS` | **No** | - | The address of a Bitcoin Electrum server you own or trust. E.g.: `localhost:50001:t` (no SSL) or `my.electrum.server:50001:s` (SSL). By leaving this blank you're letting Electrum select a random server for you, which may be a privacy concern. | +| `LITECOIN_ELECTRUM_SERVER_ADDRESS` | **No** | - | The address of a Litecoin Electrum server you own or trust. E.g.: `localhost:50001:t` (no SSL) or `my.electrum.server:50001:s` (SSL). By leaving this blank you're letting Electrum select a random server for you, which may be a privacy concern. | | `MAX_NETWORK_FEE_PERCENT` | **No** | `5` | The maximum accepted miner fee percent when auto-forwarding. Not applied to XMR. | | `MAX_SLIPPAGE_PERCENT` | **No** | `0.5` | The maximum accepted slippage percent when auto-converting. | | `BITCOIN_FEE_SOURCE` | **No** | `https://mempool.space/api/v1/fees/recommended` | The fee API source to use for Bitcoin transactions. | diff --git a/docker-compose.yml b/docker-compose.yml index 4b60d4d..a26168e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,14 @@ services: btc-electrum: build: - context: ./btc-electrum + context: ./docker/btc-electrum args: VERSION: "4.5.5" CHECKSUM_SHA512: "3bdfce2187466fff20fd67736bdf257bf95d3517de47043be411ccda558a442b8fd81d6a8da094a39a1db39a7339dcd4282e73a7f00cf6bbd70473d7ce456b0b" container_name: btc-electrum restart: unless-stopped + volumes: + - btc-data:/home/electrum/.electrum environment: - ELECTRUM_RPC_USER=${BITCOIN_ELECTRUM_RPC_USERNAME} - ELECTRUM_RPC_PASSWORD=${BITCOIN_ELECTRUM_RPC_PASSWORD} @@ -14,19 +16,44 @@ services: ltc-electrum: build: - context: ./ltc-electrum + context: ./docker/ltc-electrum args: VERSION: "release-9" - CHECKSUM_SHA512: "bdf9edef38a34b087e4c70bb663ac111545d92b48aa4e2292438ebc93948ccc6f2c1b7e1b6384097ce13a8298919316e4b8863f0186764c0712245567aa4d73f" + CHECKSUM_SHA512: "62248d5eba9b7d67facb767ff35706ef3e3dcd69c6b6fb8fb67b09bc07e52193ecd59f122388d401e854385b2e2b31fd802a9f5d56464472d893f5bc1bd394af" container_name: ltc-electrum restart: unless-stopped + cap_add: + - SYS_ADMIN + devices: + - /dev/fuse:/dev/fuse + volumes: + - ltc-data:/home/electrum-ltc/.electrum environment: - ELECTRUM_RPC_USER=${LITECOIN_ELECTRUM_RPC_USERNAME} - ELECTRUM_RPC_PASSWORD=${LITECOIN_ELECTRUM_RPC_PASSWORD} - ELECTRUM_SERVER_ADDRESS=${LITECOIN_ELECTRUM_SERVER_ADDRESS} + # ltc-mweb-electrum: + # build: + # context: ./docker/ltc-electrum + # args: + # VERSION: "release-9" + # CHECKSUM_SHA512: "62248d5eba9b7d67facb767ff35706ef3e3dcd69c6b6fb8fb67b09bc07e52193ecd59f122388d401e854385b2e2b31fd802a9f5d56464472d893f5bc1bd394af" + # container_name: ltc-mweb-electrum + # restart: unless-stopped + # cap_add: + # - SYS_ADMIN + # devices: + # - "/dev/fuse" + # volumes: + # - ltc-mweb-data:/home/electrum-ltc/.electrum + # environment: + # - ELECTRUM_RPC_USER=${LITECOIN_ELECTRUM_RPC_USERNAME} + # - ELECTRUM_RPC_PASSWORD=${LITECOIN_ELECTRUM_RPC_PASSWORD} + # - ELECTRUM_SERVER_ADDRESS=${LITECOIN_ELECTRUM_SERVER_ADDRESS} + monero-wallet-rpc: - image: ghcr.io/sethforprivacy/simple-monero-wallet-rpc:latest + image: sethsimmons/simple-monero-wallet-rpc:latest restart: unless-stopped container_name: monero-wallet-rpc volumes: @@ -51,10 +78,12 @@ services: - LITECOIN_ELECTRUM_RPC_URL=${LITECOIN_ELECTRUM_RPC_URL} - LITECOIN_ELECTRUM_RPC_USERNAME=${LITECOIN_ELECTRUM_RPC_USERNAME} - LITECOIN_ELECTRUM_RPC_PASSWORD=${LITECOIN_ELECTRUM_RPC_PASSWORD} + - LITECOIN_MWEB_ELECTRUM_RPC_URL=${LITECOIN_MWEB_ELECTRUM_RPC_URL} - BITCOIN_ELECTRUM_SERVER_ADDRESS=${BITCOIN_ELECTRUM_SERVER_ADDRESS} - LITECOIN_ELECTRUM_SERVER_ADDRESS=${LITECOIN_ELECTRUM_SERVER_ADDRESS} - BITCOIN_WALLET_SEED=${BITCOIN_WALLET_SEED} - LITECOIN_WALLET_SEED=${LITECOIN_WALLET_SEED} + - LITECOIN_MWEB_WALLET_SEED=${LITECOIN_MWEB_WALLET_SEED} - MONERO_RPC_URL=http://monero-wallet-rpc:18082/json_rpc - MONERO_RPC_USERNAME=${MONERO_RPC_USERNAME} - MONERO_RPC_PASSWORD=${MONERO_RPC_PASSWORD} @@ -62,6 +91,8 @@ services: - MONERO_WALLET_PASSWORD=${MONERO_WALLET_PASSWORD} - MONERO_WALLET_HEIGHT=${MONERO_WALLET_HEIGHT} command: python ./src/seed-importer.py + extra_hosts: + - "host.docker.internal:host-gateway" depends_on: - btc-electrum - ltc-electrum @@ -78,21 +109,17 @@ services: - BITCOIN_ELECTRUM_RPC_USERNAME=${BITCOIN_ELECTRUM_RPC_USERNAME} - BITCOIN_ELECTRUM_RPC_PASSWORD=${BITCOIN_ELECTRUM_RPC_PASSWORD} - LITECOIN_ELECTRUM_RPC_URL=${LITECOIN_ELECTRUM_RPC_URL} + - LITECOIN_MWEB_ELECTRUM_RPC_URL=${LITECOIN_MWEB_ELECTRUM_RPC_URL} - LITECOIN_ELECTRUM_RPC_USERNAME=${LITECOIN_ELECTRUM_RPC_USERNAME} - LITECOIN_ELECTRUM_RPC_PASSWORD=${LITECOIN_ELECTRUM_RPC_PASSWORD} - - BITCOIN_ELECTRUM_SERVER_ADDRESS=${BITCOIN_ELECTRUM_SERVER_ADDRESS} - - LITECOIN_ELECTRUM_SERVER_ADDRESS=${LITECOIN_ELECTRUM_SERVER_ADDRESS} - - BITCOIN_WALLET_SEED=${BITCOIN_WALLET_SEED} - - LITECOIN_WALLET_SEED=${LITECOIN_WALLET_SEED} - MONERO_RPC_URL=http://monero-wallet-rpc:18082/json_rpc - MONERO_RPC_USERNAME=${MONERO_RPC_USERNAME} - MONERO_RPC_PASSWORD=${MONERO_RPC_PASSWORD} - - MONERO_WALLET_SEED=${MONERO_WALLET_SEED} - - MONERO_WALLET_PASSWORD=${MONERO_WALLET_PASSWORD} - - MONERO_WALLET_HEIGHT=${MONERO_WALLET_HEIGHT} - KRAKEN_API_KEY=${KRAKEN_API_KEY} - KRAKEN_API_SECRET=${KRAKEN_API_SECRET} command: python ./src/autoforward.py + extra_hosts: + - "host.docker.internal:host-gateway" depends_on: - seed-importer @@ -110,4 +137,7 @@ services: - seed-importer volumes: + btc-data: + ltc-data: + ltc-mweb-data: monero-wallet-rpc-data: diff --git a/btc-electrum/Dockerfile b/docker/btc-electrum/Dockerfile similarity index 94% rename from btc-electrum/Dockerfile rename to docker/btc-electrum/Dockerfile index f29ac5b..1e457f9 100644 --- a/btc-electrum/Dockerfile +++ b/docker/btc-electrum/Dockerfile @@ -6,7 +6,6 @@ ARG CHECKSUM_SHA512 ENV ELECTRUM_VERSION=$VERSION ENV ELECTRUM_USER=electrum ENV ELECTRUM_HOME=/home/$ELECTRUM_USER -ENV ELECTRUM_NETWORK=mainnet RUN adduser -D $ELECTRUM_USER @@ -35,8 +34,8 @@ RUN mkdir -p /data \ COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh -USER $BTC_ELECTRUM_USER -WORKDIR $BTC_ELECTRUM_HOME +USER $BITCOIN_ELECTRUM_USER +WORKDIR $BITCOIN_ELECTRUM_HOME VOLUME /data EXPOSE 7000 diff --git a/btc-electrum/docker-entrypoint.sh b/docker/btc-electrum/docker-entrypoint.sh similarity index 89% rename from btc-electrum/docker-entrypoint.sh rename to docker/btc-electrum/docker-entrypoint.sh index d217f92..1cad5f8 100644 --- a/btc-electrum/docker-entrypoint.sh +++ b/docker/btc-electrum/docker-entrypoint.sh @@ -3,7 +3,7 @@ set -ex trap 'pkill -TERM -P1; electrum stop; exit 0' SIGTERM -rm -f .electrum/daemon +rm -f .electrum/daemon .electrum/daemon_rpc_socket electrum --offline setconfig rpcuser ${ELECTRUM_RPC_USER} electrum --offline setconfig rpcpassword ${ELECTRUM_RPC_PASSWORD} electrum --offline setconfig rpchost 0.0.0.0 diff --git a/docker/ltc-electrum/Dockerfile b/docker/ltc-electrum/Dockerfile new file mode 100644 index 0000000..e51fe64 --- /dev/null +++ b/docker/ltc-electrum/Dockerfile @@ -0,0 +1,25 @@ +FROM ubuntu:latest + +ARG VERSION +ARG CHECKSUM_SHA512 + +RUN apt update && \ + apt install -y wget libfuse2 fuse3 + +ENV ELECTRUM_VERSION=$VERSION +ENV ELECTRUM_USER=electrum +ENV ELECTRUM_HOME=/home/$ELECTRUM_USER +ENV ELECTRUM_CHECKSUM_SHA512 $CHECKSUM_SHA512 + +RUN useradd -m $ELECTRUM_USER +USER $ELECTRUM_USER +WORKDIR $ELECTRUM_HOME + +RUN wget https://github.com/ltcmweb/electrum-ltc/releases/download/${ELECTRUM_VERSION}/electrum-ltc-${ELECTRUM_VERSION}-x86_64.AppImage -O electrum-ltc.appimage +RUN [ "${ELECTRUM_CHECKSUM_SHA512} electrum-ltc.appimage" = "$(sha512sum electrum-ltc.appimage)" ] +RUN echo -e "**************************\n SHA 512 Checksum OK\n**************************" +COPY --chown=$ELECTRUM_USER:$ELECTRUM_USER ./docker-entrypoint.sh docker-entrypoint.sh +RUN chmod +x ./electrum-ltc.appimage ./docker-entrypoint.sh + +EXPOSE 7000 +ENTRYPOINT [ "./docker-entrypoint.sh" ] \ No newline at end of file diff --git a/docker/ltc-electrum/docker-entrypoint.sh b/docker/ltc-electrum/docker-entrypoint.sh new file mode 100644 index 0000000..ef8272e --- /dev/null +++ b/docker/ltc-electrum/docker-entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +trap 'pkill -TERM -P1; electrum-ltc.appimage stop; exit 0' SIGTERM + +rm -f $HOME/.electrum-ltc/daemon +./electrum-ltc.appimage --offline setconfig rpcuser ${ELECTRUM_RPC_USER} +./electrum-ltc.appimage --offline setconfig rpcpassword ${ELECTRUM_RPC_PASSWORD} +./electrum-ltc.appimage --offline setconfig rpchost 0.0.0.0 +./electrum-ltc.appimage --offline setconfig rpcport 7000 + +if [ -n "${ELECTRUM_SERVER_ADDRESS}" ]; then + ./electrum-ltc.appimage daemon -1 -s "${ELECTRUM_SERVER_ADDRESS}" "$@" +else + ./electrum-ltc.appimage daemon "$@" +fi + diff --git a/ltc-electrum/Dockerfile b/ltc-electrum/Dockerfile deleted file mode 100644 index bd65591..0000000 --- a/ltc-electrum/Dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -FROM python:3.12-alpine - -ARG VERSION -ARG CHECKSUM_SHA512 - -ENV ELECTRUM_VERSION=$VERSION -ENV ELECTRUM_USER=electrum -ENV ELECTRUM_HOME=/home/$ELECTRUM_USER -ENV ELECTRUM_NETWORK=mainnet - -RUN adduser -D $ELECTRUM_USER - -RUN mkdir -p /data ${ELECTRUM_HOME} && \ - ln -sf /data ${ELECTRUM_HOME}/.electrum && \ - chown ${ELECTRUM_USER} ${ELECTRUM_HOME}/.electrum /data - -# IMPORTANT: always verify gpg signature before changing a hash here! -ENV ELECTRUM_CHECKSUM_SHA512 $CHECKSUM_SHA512 - -RUN apk --no-cache add --virtual build-dependencies gcc musl-dev libsecp256k1 libsecp256k1-dev libressl-dev -RUN wget https://github.com/ltcmweb/electrum-ltc/archive/refs/tags/${ELECTRUM_VERSION}.tar.gz -RUN [ "${ELECTRUM_CHECKSUM_SHA512} ${ELECTRUM_VERSION}.tar.gz" = "$(sha512sum ${ELECTRUM_VERSION}.tar.gz)" ] -RUN echo -e "**************************\n SHA 512 Checksum OK\n**************************" -RUN tar -xzf ${ELECTRUM_VERSION}.tar.gz -RUN pip3 install cryptography google protobuf grpcio scrypt ${ELECTRUM_VERSION}.tar.gz -RUN rm ${ELECTRUM_VERSION}.tar.gz -RUN ln -s /usr/lib/libsecp256k1.so /usr/local/lib/python3.12/site-packages/electrum_ltc/libsecp256k1.so.0 - -RUN mkdir -p /data \ - ${ELECTRUM_HOME}/.electrum/wallets/ \ - ${ELECTRUM_HOME}/.electrum/testnet/wallets/ \ - ${ELECTRUM_HOME}/.electrum/regtest/wallets/ \ - ${ELECTRUM_HOME}/.electrum/simnet/wallets/ && \ - ln -sf ${ELECTRUM_HOME}/.electrum/ /data && \ - chown -R ${ELECTRUM_USER} ${ELECTRUM_HOME}/.electrum /data - -COPY docker-entrypoint.sh /usr/local/bin/ -RUN chmod +x /usr/local/bin/docker-entrypoint.sh - -USER $ELECTRUM_USER -WORKDIR $ELECTRUM_HOME -VOLUME /data -EXPOSE 7000 - -ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/ltc-electrum/docker-entrypoint.sh b/ltc-electrum/docker-entrypoint.sh deleted file mode 100644 index 0b785a1..0000000 --- a/ltc-electrum/docker-entrypoint.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env sh -set -ex - -trap 'pkill -TERM -P1; electrum-ltc stop; exit 0' SIGTERM - -rm -f .electrum/daemon -electrum-ltc --offline setconfig rpcuser ${ELECTRUM_RPC_USER} -electrum-ltc --offline setconfig rpcpassword ${ELECTRUM_RPC_PASSWORD} -electrum-ltc --offline setconfig rpchost 0.0.0.0 -electrum-ltc --offline setconfig rpcport 7000 - -if [ -n "${LITECOIN_ELECTRUM_SERVER_ADDRESS}" ]; then - electrum-ltc daemon -1 -s "${LITECOIN_ELECTRUM_SERVER_ADDRESS}" "$@" -else - electrum-ltc daemon "$@" -fi - diff --git a/poetry.lock b/poetry.lock index d853a8d..a83ffe4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "asn1crypto" @@ -6,6 +6,7 @@ version = "1.5.1" description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, @@ -17,6 +18,7 @@ version = "2.9.3" description = "Generation of mnemonics, seeds, private/public keys and addresses for different types of cryptocurrencies" optional = false python-versions = ">=3.7" +groups = ["main"] files = [ {file = "bip_utils-2.9.3-py3-none-any.whl", hash = "sha256:ee26b8417a576c7f89b847da37316db01a5cece1994c1609d37fbeefb91ad45e"}, {file = "bip_utils-2.9.3.tar.gz", hash = "sha256:72a8c95484b57e92311b0b2a3d5195b0ce4395c19a0b157d4a289e8b1300f48a"}, @@ -41,6 +43,7 @@ version = "5.6.4" description = "CBOR (de)serializer with extensive tag support" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "cbor2-5.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c40c68779a363f47a11ded7b189ba16767391d5eae27fac289e7f62b730ae1fc"}, {file = "cbor2-5.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0625c8d3c487e509458459de99bf052f62eb5d773cc9fc141c6a6ea9367726d"}, @@ -83,7 +86,7 @@ files = [ [package.extras] benchmarks = ["pytest-benchmark (==4.0.0)"] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)", "typing-extensions"] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.3.0)", "typing-extensions ; python_version < \"3.12\""] test = ["coverage (>=7)", "hypothesis", "pytest"] [[package]] @@ -92,6 +95,7 @@ version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, @@ -103,6 +107,7 @@ version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, @@ -182,6 +187,7 @@ version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" +groups = ["main"] files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, @@ -281,6 +287,7 @@ version = "20.0.0" description = "Cross-platform Python CFFI bindings for libsecp256k1" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "coincurve-20.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d559b22828638390118cae9372a1bb6f6594f5584c311deb1de6a83163a0919b"}, {file = "coincurve-20.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33d7f6ebd90fcc550f819f7f2cce2af525c342aac07f0ccda46ad8956ad9d99b"}, @@ -347,6 +354,7 @@ version = "1.7" description = "CRC Generator" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "crcmod-1.7.tar.gz", hash = "sha256:dc7051a0db5f2bd48665a990d3ec1cc305a466a77358ca4492826f41f283601e"}, ] @@ -357,6 +365,7 @@ version = "0.19.0" description = "ECDSA cryptographic signature library (pure python)" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.6" +groups = ["main"] files = [ {file = "ecdsa-0.19.0-py2.py3-none-any.whl", hash = "sha256:2cea9b88407fdac7bbeca0833b189e4c9c53f2ef1e1eaa29f6224dbc809b707a"}, {file = "ecdsa-0.19.0.tar.gz", hash = "sha256:60eaad1199659900dd0af521ed462b793bbdf867432b3948e87416ae4caf6bf8"}, @@ -375,6 +384,7 @@ version = "1.4.1" description = "Ed25519 public-key signatures (BLAKE2b fork)" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "ed25519-blake2b-1.4.1.tar.gz", hash = "sha256:731e9f93cd1ac1a64649575f3519a99ffe0bb1e4cf7bf5f5f0be513a39df7363"}, ] @@ -385,6 +395,7 @@ version = "3.8" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, @@ -396,6 +407,7 @@ version = "0.2.0" description = "Python bindings for sr25519 library" optional = false python-versions = "*" +groups = ["main"] files = [ {file = "py_sr25519_bindings-0.2.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:86cc1a571852a4f2ade827ebf211e066b23ab805d3e864cbe213a3d8cd53f7d5"}, {file = "py_sr25519_bindings-0.2.0-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:453c9088e39dd04b07bf3ada6c473a5349c4dfd965009a35124b2c807117eda8"}, @@ -477,6 +489,7 @@ version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, @@ -488,6 +501,7 @@ version = "3.20.0" description = "Cryptographic library for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] files = [ {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, @@ -529,6 +543,7 @@ version = "1.5.0" description = "Python binding to the Networking and Cryptography (NaCl) library" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ {file = "PyNaCl-1.5.0-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1"}, {file = "PyNaCl-1.5.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92"}, @@ -555,6 +570,7 @@ version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, @@ -576,6 +592,7 @@ version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["main"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, @@ -587,18 +604,19 @@ version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.12" content-hash = "312bfc0d67e89feee1abbdbabc31649ff525b844d43eeaa06d57b9e9d26fbf06" diff --git a/pyproject.toml b/pyproject.toml index 6279b03..2b511d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ python = "^3.12" requests = "^2.32.3" bip-utils = "^2.9.3" - [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/src/autoforward.py b/src/autoforward.py index 7e21fa2..a6d8de7 100644 --- a/src/autoforward.py +++ b/src/autoforward.py @@ -8,29 +8,46 @@ from constants import MIN_BITCOIN_SEND_AMOUNT, MIN_LITECOIN_SEND_AMOUNT, MIN_MON import util import env -def get_fee_rate(source: str, rate: str) -> int: +ElectrumCoin = Literal['btc', 'ltc', 'ltc-mweb'] + +def get_fee_rate(coin: ElectrumCoin) -> int: + coin_to_source: dict[ElectrumCoin, str] = { + 'btc': env.BITCOIN_FEE_SOURCE, + 'ltc': env.LITECOIN_FEE_SOURCE, + 'ltc-mweb': env.LITECOIN_FEE_SOURCE + } + + coin_to_rate: dict[ElectrumCoin, str] = { + 'btc': env.BITCOIN_FEE_RATE, + 'ltc': env.LITECOIN_FEE_RATE, + 'ltc-mweb': env.LITECOIN_FEE_RATE + } + + source = coin_to_source[coin] + rate = coin_to_rate[coin] + return requests.get(source).json()[rate] -def set_electrum_fee_rate(coin: Literal['btc', 'ltc'], rate: int, dynamic: bool): +def set_electrum_fee_rate(coin: ElectrumCoin, rate: int, dynamic: bool): if dynamic: # Fall back to the Electrum rate if there is an issue util.request_electrum_rpc(coin, 'setconfig', ['dynamic_fees', True]) else: util.request_electrum_rpc(coin, 'setconfig', ['dynamic_fees', False]) util.request_electrum_rpc(coin, 'setconfig', ['fee_per_kb', rate * 1000]) -def get_electrum_balance(coin: Literal['btc', 'ltc']) -> float: +def get_electrum_balance(coin: ElectrumCoin) -> float: return float(util.request_electrum_rpc(coin, 'getbalance')['confirmed']) -def create_psbt(coin: Literal['btc', 'ltc'], destination_address: str) -> str: +def create_psbt(coin: ElectrumCoin, destination_address: str, unsigned = True) -> str: params = { 'destination': destination_address, 'amount': '!', - 'unsigned': True # This way we can get the input amounts + 'unsigned': unsigned # This way we can get the input amounts } return util.request_electrum_rpc(coin, 'payto', params) -def get_psbt_data(coin: Literal['btc', 'ltc'], psbt: str) -> dict: +def get_psbt_data(coin: ElectrumCoin, psbt: str) -> dict: return util.request_electrum_rpc(coin, 'deserialize', [psbt]) def get_total_psbt_fee(psbt_data: dict) -> float: @@ -47,10 +64,10 @@ def get_total_psbt_fee(psbt_data: dict) -> float: total_fee = total_fee_sats / 100000000 return total_fee -def sign_psbt(coin: Literal['btc', 'ltc'], psbt: str) -> str: +def sign_psbt(coin: ElectrumCoin, psbt: str) -> str: return cast(str, util.request_electrum_rpc(coin, 'signtransaction', [psbt])) -def broadcast_electrum_tx(coin: Literal['btc', 'ltc'], signed_tx: str): +def broadcast_electrum_tx(coin: ElectrumCoin, signed_tx: str): util.request_electrum_rpc(coin, 'broadcast', [signed_tx]) def get_monero_balance() -> float: @@ -91,87 +108,62 @@ def get_new_kraken_address(asset: Literal['btc', 'ltc', 'xmr']) -> str: raise Exception(f'Kraken did not return a new address: {json.dumps(result, indent=2)}') -def attempt_bitcoin_autoforward(): - balance = get_electrum_balance('btc') +def attempt_electrum_autoforward(coin: ElectrumCoin): + coin_upper = coin.upper() + balance = get_electrum_balance(coin) + + coin_to_min_send: dict[ElectrumCoin, float] = { + 'btc': MIN_BITCOIN_SEND_AMOUNT, + 'ltc': MIN_LITECOIN_SEND_AMOUNT, + 'ltc-mweb': MIN_LITECOIN_SEND_AMOUNT + } + + min_send = coin_to_min_send[coin] if balance < MIN_BITCOIN_SEND_AMOUNT: - print(util.get_time(), f'Not enough Bitcoin balance to autoforward. (Balance: {balance}, Min Send: {MIN_BITCOIN_SEND_AMOUNT})') + print(util.get_time(), f'Not enough {coin_upper} balance to autoforward. (Balance: {balance}, Min. send: {min_send})') return try: - fee_rate = get_fee_rate(env.BITCOIN_FEE_SOURCE, env.BITCOIN_FEE_RATE) - set_electrum_fee_rate('btc', fee_rate, dynamic=False) + fee_rate = get_fee_rate(coin) + set_electrum_fee_rate(coin, fee_rate, dynamic=False) except: - set_electrum_fee_rate('btc', rate=0, dynamic=True) - address = get_new_kraken_address('btc') + set_electrum_fee_rate(coin, rate=0, dynamic=True) + address = get_new_kraken_address(coin if coin != 'ltc-mweb' else 'ltc') - try: - psbt = create_psbt('btc', address) - except requests.exceptions.HTTPError as http_error: - response_json = cast(dict, http_error.response.json()) + # Electrum-ltc doesn't support deserializing mweb transactions, so we can't check total fee + if coin != 'ltc-mweb': + try: + psbt = create_psbt(coin, address) + except requests.exceptions.HTTPError as http_error: + response_json = cast(dict, http_error.response.json()) - if response_json.get('error', {}).get('data', {}).get('exception', '') == 'NotEnoughFunds()': - print(util.get_time(), f'Not autoforwarding due to high transaction fee.') - return + if response_json.get('error', {}).get('data', {}).get('exception', '') == 'NotEnoughFunds()': + print(util.get_time(), f'Not autoforwarding due to high transaction fee.') + return - raise http_error + raise http_error - psbt_data = get_psbt_data('btc', psbt) - total_fee = get_total_psbt_fee(psbt_data) - amount = balance + psbt_data = get_psbt_data(coin, psbt) + total_fee = get_total_psbt_fee(psbt_data) + amount = balance - if total_fee / amount * 100 > env.MAX_NETWORK_FEE_PERCENT: - print(util.get_time(), f'Not autoforwarding due to high transaction fee {total_fee} BTC.') - return + if total_fee / amount * 100 > env.MAX_NETWORK_FEE_PERCENT: + print(util.get_time(), f'Not autoforwarding due to high transaction fee ({total_fee} {coin_upper}).') + return - signed_tx = sign_psbt('btc', psbt) - broadcast_electrum_tx('btc', signed_tx) + signed_tx = sign_psbt(coin, psbt) + else: + signed_tx = create_psbt(coin, address, unsigned=False) - print(util.get_time(), f'Autoforwarded {amount} BTC to {address}!') - -def attempt_litecoin_autoforward(): - balance = get_electrum_balance('ltc') - - if balance < MIN_LITECOIN_SEND_AMOUNT: - print(util.get_time(), f'Not enough Litecoin balance to autoforward. (Balance: {balance}, Min Send: {MIN_LITECOIN_SEND_AMOUNT})') - return - - try: - fee_rate = get_fee_rate(env.LITECOIN_FEE_SOURCE, env.LITECOIN_FEE_RATE) - set_electrum_fee_rate('ltc', fee_rate, dynamic=False) - except: - set_electrum_fee_rate('ltc', rate=0, dynamic=True) - address = get_new_kraken_address('ltc') - - try: - psbt = create_psbt('ltc', address) - except requests.exceptions.HTTPError as http_error: - response_json = cast(dict, http_error.response.json()) - - if response_json.get('error', {}).get('data', {}).get('exception', '') == 'NotEnoughFunds()': - print(util.get_time(), f'Not autoforwarding due to high transaction fee.') - return - - raise http_error - - psbt_data = get_psbt_data('ltc', psbt) - total_fee = get_total_psbt_fee(psbt_data) - amount = balance - - if total_fee / amount * 100 > env.MAX_NETWORK_FEE_PERCENT: - print(util.get_time(), f'Not autoforwarding due to high transaction fee {total_fee} LTC.') - return - - signed_tx = sign_psbt('ltc', psbt) - broadcast_electrum_tx('ltc', signed_tx) - - print(util.get_time(), f'Autoforwarded {amount} LTC to {address}!') + broadcast_electrum_tx(coin, signed_tx) + print(util.get_time(), f'Autoforwarded {amount} {coin_upper} to {address}!') def attempt_monero_autoforward(): balance = get_monero_balance() if balance < MIN_MONERO_SEND_AMOUNT: - print(util.get_time(), f'Not enough Monero balance to autoforward. (Balance: {balance}, Min Send: {MIN_MONERO_SEND_AMOUNT})') + print(util.get_time(), f'Not enough XMR balance to autoforward. (Balance: {balance}, Min Send: {MIN_MONERO_SEND_AMOUNT})') return address = get_new_kraken_address('xmr') @@ -183,21 +175,27 @@ util.wait_for_wallets() while 1: try: - attempt_bitcoin_autoforward() + attempt_electrum_autoforward('btc') except Exception as e: - print(util.get_time(), 'Error autoforwarding bitcoin:') + print(util.get_time(), 'Error autoforwarding Bitcoin:') print(traceback.format_exc()) try: - attempt_litecoin_autoforward() + attempt_electrum_autoforward('ltc') except Exception as e: print(util.get_time(), 'Error autoforwarding litecoin:') print(traceback.format_exc()) + + # try: + # attempt_electrum_autoforward('ltc-mweb') + # except Exception as e: + # print(util.get_time(), 'Error autoforwarding Litecoin MWEB:') + # print(traceback.format_exc()) try: attempt_monero_autoforward() except Exception as e: - print(util.get_time(), 'Error autoforwarding monero:') + print(util.get_time(), 'Error autoforwarding Monero:') print(traceback.format_exc()) sleep(60 * 5) diff --git a/src/constants.py b/src/constants.py index 65721a2..d894ea1 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,3 +1,3 @@ MIN_BITCOIN_SEND_AMOUNT = 0.0001 MIN_LITECOIN_SEND_AMOUNT = 0.05 -MIN_MONERO_SEND_AMOUNT = 0.03 \ No newline at end of file +MIN_MONERO_SEND_AMOUNT = 0.03 diff --git a/src/env.py b/src/env.py index b4df8fb..53d76a0 100644 --- a/src/env.py +++ b/src/env.py @@ -6,10 +6,12 @@ BITCOIN_ELECTRUM_RPC_USERNAME = os.getenv('BITCOIN_ELECTRUM_RPC_USERNAME', '') BITCOIN_ELECTRUM_RPC_PASSWORD = os.getenv('BITCOIN_ELECTRUM_RPC_PASSWORD', '') LITECOIN_ELECTRUM_RPC_USERNAME = os.getenv('LITECOIN_ELECTRUM_RPC_USERNAME', '') LITECOIN_ELECTRUM_RPC_PASSWORD = os.getenv('LITECOIN_ELECTRUM_RPC_PASSWORD', '') +LITECOIN_MWEB_ELECTRUM_RPC_URL = os.getenv('LITECOIN_MWEB_ELECTRUM_RPC_URL', '') BITCOIN_ELECTRUM_SERVER_ADDRESS = os.getenv('BITCOIN_ELECTRUM_SERVER_ADDRESS', '') LITECOIN_ELECTRUM_SERVER_ADDRESS = os.getenv('LITECOIN_ELECTRUM_SERVER_ADDRESS', '') BITCOIN_WALLET_SEED = os.getenv('BITCOIN_WALLET_SEED', '') LITECOIN_WALLET_SEED = os.getenv('LITECOIN_WALLET_SEED', '') +LITECOIN_MWEB_WALLET_SEED = os.getenv('LITECOIN_MWEB_WALLET_SEED', '') MONERO_RPC_URL = os.getenv('MONERO_RPC_URL', 'http://monero-wallet-rpc:18082/json_rpc') MONERO_RPC_USERNAME = os.getenv('MONERO_RPC_USERNAME', '') diff --git a/src/seed-importer.py b/src/seed-importer.py index b0c2ad6..0a44ce7 100644 --- a/src/seed-importer.py +++ b/src/seed-importer.py @@ -1,10 +1,11 @@ from typing import Literal from bip_utils import Bip39SeedGenerator, Bip84, Bip84Coins import traceback + import util import env -def get_zprv_from_seed(coin: Literal['btc', 'ltc'], mnemonic: str ) -> str: +def get_xprv_from_mnemonic(coin: Literal['btc', 'ltc',], mnemonic: str ) -> str: coin_type = Bip84Coins.BITCOIN if coin == 'btc' else Bip84Coins.LITECOIN seed_bytes = Bip39SeedGenerator(mnemonic).Generate() bip84_master_key = Bip84.FromSeed(seed_bytes, coin_type) @@ -12,12 +13,15 @@ def get_zprv_from_seed(coin: Literal['btc', 'ltc'], mnemonic: str ) -> str: return zprv def import_bitcoin_seed(): - zprv = get_zprv_from_seed('btc', env.BITCOIN_WALLET_SEED) - util.request_electrum_rpc('btc', 'restore', [zprv]) + xprv = get_xprv_from_mnemonic('btc', env.BITCOIN_WALLET_SEED) + util.request_electrum_rpc('btc', 'restore', [xprv]) def import_litecoin_seed(): - zprv = get_zprv_from_seed('ltc', env.LITECOIN_WALLET_SEED) - util.request_electrum_rpc('ltc', 'restore', [zprv]) + xprv = get_xprv_from_mnemonic('ltc', env.LITECOIN_WALLET_SEED) + util.request_electrum_rpc('ltc', 'restore', [xprv]) + +def import_litecoin_mweb_seed(): + util.request_electrum_rpc('ltc-mweb', 'restore', [env.LITECOIN_MWEB_WALLET_SEED]) def import_monero_seed(): params = { @@ -51,6 +55,15 @@ except Exception as e: print(util.get_time(), 'Error importing litecoin seed:') print(traceback.format_exc()) +# try: +# import_litecoin_mweb_seed() +# util.request_electrum_rpc('ltc-mweb', 'load_wallet') +# util.request_electrum_rpc('ltc-mweb', 'changegaplimit', [1000, 'iknowhatimdoing']) +# print('Litecoin mimblewimble seed has successfully been imported!') +# except Exception as e: +# print(util.get_time(), 'Error importing litecoin mimblewimble seed:') +# print(traceback.format_exc()) + try: import_monero_seed() print('Monero seed has successfully been imported!') diff --git a/src/util.py b/src/util.py index 287194d..8b271c7 100644 --- a/src/util.py +++ b/src/util.py @@ -15,13 +15,20 @@ import env def get_time() -> str: return f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}]' -def request_electrum_rpc(coin: Literal['btc', 'ltc'], method: str, params: list | dict = []): +def request_electrum_rpc(coin: Literal['btc', 'ltc', 'ltc-mweb'], method: str, params: list | dict = []): headers = {'content-type': 'application/json'} - if coin == 'btc': - auth = (env.BITCOIN_ELECTRUM_RPC_USERNAME, env.BITCOIN_ELECTRUM_RPC_PASSWORD) - else: - auth = (env.LITECOIN_ELECTRUM_RPC_USERNAME, env.LITECOIN_ELECTRUM_RPC_PASSWORD) + coin_to_auth = { + 'btc': (env.BITCOIN_ELECTRUM_RPC_USERNAME, env.BITCOIN_ELECTRUM_RPC_PASSWORD), + 'ltc': (env.LITECOIN_ELECTRUM_RPC_USERNAME, env.LITECOIN_ELECTRUM_RPC_PASSWORD), + 'ltc-mweb': (env.LITECOIN_ELECTRUM_RPC_USERNAME, env.LITECOIN_ELECTRUM_RPC_PASSWORD) + } + + coin_to_url = { + 'btc': env.BITCOIN_ELECTRUM_RPC_URL, + 'ltc': env.LITECOIN_ELECTRUM_RPC_URL, + 'ltc-mweb': env.LITECOIN_MWEB_ELECTRUM_RPC_URL + } data = { 'jsonrpc': '2.0', @@ -31,10 +38,10 @@ def request_electrum_rpc(coin: Literal['btc', 'ltc'], method: str, params: list } response = requests.post( - env.BITCOIN_ELECTRUM_RPC_URL if coin == 'btc' else env.LITECOIN_ELECTRUM_RPC_URL, + coin_to_url[coin], headers=headers, data=json.dumps(data), - auth=auth + auth=coin_to_auth[coin] ) response_json = response.json() @@ -78,6 +85,9 @@ def open_bitcoin_wallet(): def open_litecoin_wallet(): request_electrum_rpc('ltc', 'load_wallet') +def open_litecoin_mweb_wallet(): + request_electrum_rpc('ltc-mweb', 'load_wallet') + def open_monero_wallet() -> None: params = {'filename': 'foo', 'password': env.MONERO_WALLET_PASSWORD} request_monero_rpc('open_wallet', params) @@ -130,6 +140,15 @@ def wait_for_wallets(): break except: time.sleep(10) + + print('Waiting for Litecoin MWEB wallet...') + + while 1: + try: + open_litecoin_mweb_wallet() + break + except: + time.sleep(10) print('Waiting for Monero wallet...')